Skip to content

Commit

Permalink
1348/Add photo upload to the Listing form (#1491)
Browse files Browse the repository at this point in the history
* First pass at a dropzone Cloudinary uploader

* Style the progress control and provide more complete flow

* Tighten up Dropzone usability

* Add id for accessibility

* Update Changelog with #1437

* Adding photo upload to Listings MVP (WIP)

* Fix image data issue for edits, add detail preview

* Upload to Cloudinary using a signed preset

* Revert previous double-submit issue

* Remove stray console call

* Fix undefined error on new listing page

* fix lint error

* Add #1491 to changelog

* Use state only for Cloudinary upload data

Co-authored-by: seanmalbert <[email protected]>
  • Loading branch information
jaredcwhite and seanmalbert authored Jul 19, 2021
1 parent b650a05 commit ef05c8b
Show file tree
Hide file tree
Showing 21 changed files with 389 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file. The format
- refactors listing form submit to fix double submit issue ([#1501](https://github.com/bloom-housing/bloom/pull/1501))

- Added:
- Photo upload and preview to the Partner Listing screens ([#1491](https://github.com/bloom-housing/bloom/pull/1491)) (Jared White)
- AG-grid sorting now is connected with the backend sorting ([#1083](https://github.com/bloom-housing/bloom/issues/1083)) (Michał Plebański)

### UI Components
Expand Down
8 changes: 7 additions & 1 deletion backend/core/src/assets/services/upload.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ export class CloudinaryService implements UploadService {

createPresignedUploadMetadata(parametersToSign: Record<string, string>): { signature: string } {
// Based on https://cloudinary.com/documentation/upload_images#signed_upload_video_tutorial

const parametersToSignWithTimestamp = {
timestamp: parseInt(parametersToSign.timestamp),
...parametersToSign,
}

const signature = cloudinary.utils.api_sign_request(
parametersToSign,
parametersToSignWithTimestamp,
this.configService.get<string>("CLOUDINARY_SECRET")
)
return {
Expand Down
3 changes: 3 additions & 0 deletions sites/partners/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ NEXTJS_PORT=3001
SHOW_DUPLICATES=FALSE
PUBLIC_BASE_URL=http://localhost:3000
SHOW_LM_LINKS=TRUE
CLOUDINARY_CLOUD_NAME=exygy
CLOUDINARY_KEY='abcxyz'
CLOUDINARY_SIGNED_PRESET='test123'
3 changes: 3 additions & 0 deletions sites/partners/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ module.exports = withCSS(
showDuplicates: process.env.SHOW_DUPLICATES === "TRUE",
publicBaseUrl: process.env.PUBLIC_BASE_URL,
showLMLinks: process.env.SHOW_LM_LINKS === "TRUE",
cloudinaryCloudName: process.env.CLOUDINARY_CLOUD_NAME,
cloudinaryKey: process.env.CLOUDINARY_KEY,
cloudinarySignedPreset: process.env.CLOUDINARY_SIGNED_PRESET,
},
i18n: {
locales: process.env.LANGUAGES ? process.env.LANGUAGES.split(",") : ["en"],
Expand Down
9 changes: 9 additions & 0 deletions sites/partners/pages/listings/[id]/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ const NewListing = () => {

if (!listingDto) return false

// Set listing photo from assets if necessary:
if (listingDto.image == null && listingDto.assets.length > 0) {
listingDto.image = listingDto.assets.find((asset) => asset.label == "building")
}
// If that didn't do the trick, set a default:
if (listingDto.image == null) {
listingDto.image = { fileId: "", label: "" }
}

return (
<ListingContext.Provider value={listingDto}>
<Layout>
Expand Down
2 changes: 2 additions & 0 deletions sites/partners/pages/listings/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Aside from "../../../src/listings/Aside"
import { ListingContext } from "../../../src/listings/ListingContext"
import DetailListingData from "../../../src/listings/PaperListingDetails/sections/DetailListingData"
import DetailListingIntro from "../../../src/listings/PaperListingDetails/sections/DetailListingIntro"
import DetailListingPhoto from "../../../src/listings/PaperListingDetails/sections/DetailListingPhoto"
import DetailBuildingDetails from "../../../src/listings/PaperListingDetails/sections/DetailBuildingDetails"
import DetailAdditionalDetails from "../../../src/listings/PaperListingDetails/sections/DetailAdditionalDetails"
import DetailAdditionalEligibility from "../../../src/listings/PaperListingDetails/sections/DetailAdditionalEligibility"
Expand Down Expand Up @@ -112,6 +113,7 @@ export default function ApplicationsList() {
<div className="info-card md:w-9/12">
<DetailListingData />
<DetailListingIntro />
<DetailListingPhoto />
<DetailBuildingDetails />
<DetailUnits setUnitDrawer={setUnitDrawer} />
<DetailAdditionalFees />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useContext } from "react"
import {
cloudinaryUrlFromId,
t,
GridSection,
GridCell,
MinimalTable,
TableThumbnail,
} from "@bloom-housing/ui-components"
import { ListingContext } from "../../ListingContext"

const DetailListingPhoto = () => {
const listing = useContext(ListingContext)

let listingFormPhoto = listing.image

// Set listing photo from assets if necessary:
if (listing.image == null && listing.assets.length > 0) {
listingFormPhoto = listing.assets.find((asset) => asset.label == "building")
}
const listingPhotoUrl = /https?:\/\//.exec(listingFormPhoto.fileId)
? listingFormPhoto.fileId
: cloudinaryUrlFromId(listingFormPhoto.fileId)

const photoTableHeaders = {
preview: "t.preview",
fileName: "t.fileName",
}
const photoTableData = [
{
preview: (
<TableThumbnail>
<img src={listingPhotoUrl} />
</TableThumbnail>
),
fileName: listingFormPhoto.fileId.split("/").slice(-1).join(),
},
]

return (
<GridSection
className="bg-primary-lighter"
title={t("listings.sections.photoTitle")}
grid={false}
inset
>
<GridSection>
<GridCell span={2}>
<MinimalTable headers={photoTableHeaders} data={photoTableData}></MinimalTable>
</GridCell>
</GridSection>
</GridSection>
)
}

export default DetailListingPhoto
3 changes: 3 additions & 0 deletions sites/partners/src/listings/PaperListingForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import Units from "./sections/Units"
import { stringToBoolean, stringToNumber } from "../../../lib/helpers"
import BuildingDetails from "./sections/BuildingDetails"
import ListingIntro from "./sections/ListingIntro"
import ListingPhoto from "./sections/ListingPhoto"
import BuildingFeatures from "./sections/BuildingFeatures"
import RankingsAndResults from "./sections/RankingsAndResults"
import ApplicationAddress from "./sections/ApplicationAddress"
Expand Down Expand Up @@ -120,6 +121,7 @@ const defaults: FormListing = {
disableUnitsAccordion: false,
displayWaitlistSize: false,
events: [],
image: { fileId: "", label: "" },
leasingAgentAddress: defaultAddress,
leasingAgentEmail: "[email protected]",
leasingAgentName: "",
Expand Down Expand Up @@ -401,6 +403,7 @@ const ListingForm = ({ listing, editMode }: ListingFormProps) => {
<div className="flex flex-row flex-wrap">
<div className="info-card md:w-9/12">
<ListingIntro />
<ListingPhoto />
<BuildingDetails />
<Units
units={units}
Expand Down
Loading

0 comments on commit ef05c8b

Please sign in to comment.