Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sk.cl.upload site image #295

Merged
merged 29 commits into from
Apr 18, 2024
Merged

Sk.cl.upload site image #295

merged 29 commits into from
Apr 18, 2024

Conversation

CiciLing
Copy link
Contributor

@CiciLing CiciLing commented Oct 22, 2023

Checklist

  • 1. Run yarn run check
  • 2. Run yarn run test

Why

Resolves #241

This ticket allows the end users to upload their tree image to their adopted tree. Previously, there was no way of uploading tree images through the site and thus this will come in handy to users who want to upload their tree photos to share with other users.

This PR

This change adds an upload image component to the tree pages. Users are able to upload tree images that are converted to b64. The upload image component with its API client 'uploadImage' posts the uploaded image and siteEntryId to /api/v1/protected/sites/site_image/${siteEntryId}. Note that you have to adopt the tree to be able to upload a tree image.

Screenshots

Screen Shot 2023-10-22 at 3 48 12 PM Screen Shot 2023-10-22 at 3 48 53 PM Screen Shot 2023-10-22 at 3 49 13 PM

Screen recording

Screen.Recording.2023-10-22.at.3.56.59.PM.mov

Verification Steps

To check if this upload component works, try uploading an image and go to AWS to see if the image shows up in folder 'sfft-user-upload' - (the content you defined in 'aws_s3_upload_dir' in server.properties from the backend). Additionally, there are three tests we could run in protectedApiClient.test to test upload image API client.

Copy link
Contributor

@huang0h huang0h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work guys!! A couple comments/questions about style and features:

Comment on lines 167 to 169
{userOwnsTree && treePresent && (
<TreePageUploadSiteImageButton siteData={siteData} />
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ I think we decided to allow anybody to upload images for a site, so we don't need to check if userOwnsTree here (sorry if the API doc said otherwise, I really need to clean that up 😞)

Comment on lines 244 to 252
interface TreeUploadProps {
readonly siteData: SiteProps;
}

const TreePageUploadSiteImageButton: React.FC<TreeUploadProps> = ({
siteData,
}) => {
return <UploadSiteImageButton siteEntryId={siteData.entries[0].id} />;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Just curious, how come we have this extra component rather than directly using UploadSiteImageButton? Was there some weird bug that didn't show the button without this?


const props: UploadProps = {
name: 'file',
multiple: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Do we want to allow users to upload multiple images at a time? It'd be nice quality of life feature for users, but it'd take a bit more work to upload each image and handle individual errors. If not, I think we should add the maxCount prop as 1 (more info in the component doc) so it's clear to users that they can only upload one image at time.

Comment on lines 84 to 90
<Modal
title={t('uploadSiteImage.upload_title')} // pass on as input
visible={showMenu}
footer={null}
onCancel={() => setShowMenu(false)}
closeIcon={<StyledClose />}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 Can we add a way for users to choose to upload their images anonymously? This would make it so when we view their images, it'll hide their username (as opposed to displaying it publicly). Something like a switch or a similar input would work well - make sure to update the API route to use this value as well!

return (
<>
<GreenButton
type="text"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ Just a quick style nitpick - can we change this button's type to primary? This will keep the upload button's appearance consistent with the adopt button when we hover over it (white text on light green, vs. black text on white like it is now)

@@ -2186,4 +2186,61 @@ describe('Admin Protected Client Routes', () => {
expect(result).toEqual(response);
});
});

describe('uploadImage', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

Copy link
Contributor

@huang0h huang0h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks awesome! Just a couple comments:


const props: UploadProps = {
name: 'file',
multiple: false,
multiple: true,
beforeUpload: async (file) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Just curious, did making these functions async make a difference on your end? When I got rid of the async/await, it didn't seem to make much of a difference, and looking at the upload props, it doesn't look like they need to be async functions - we should probably avoid async stuff if we can since it adds more complexity.

message.success('Sent!');
setShowMenu(!showMenu);
if (imageToUpload.length > 0) {
imageToUpload.forEach((image) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ Can we use Promise.allSettled (mdn reference) to handle all of these requests? This way, we can wait until all of them finish and handle all the results together with something like this:

const requests: Promise<void>[] = [];
imageToUpload.forEach((image) => {
  if (image) {
    requests.push(
      protectedApiClient.uploadImage(siteEntryId, image, anonymousUpload),
    );
  }
});

Promise.allSettled(requests)
  .then((results) => {
    // results contains a list of resolved promises
  })
  .finally(() => dispatch(getSiteData(id)));

@@ -102,6 +118,13 @@ const UploadSiteImageButton: React.FC<UploadImageProps> = ({ siteEntryId }) => {
<ConfirmUpload onClick={onClickUploadSiteImage}>
{t('uploadSiteImage.upload_button_message')}
</ConfirmUpload>
<Checkbox
onChange={async (e: CheckboxChangeEvent) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Similar to the beforeChange async function above - this seemed to work without being async, did it make a difference for you?

SurabhiKeesara added 2 commits December 3, 2023 13:57
Copy link
Contributor

@huang0h huang0h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! I wasn't able to figure out a way to get selecting multiple files in the file dialog to work (but we can still upload multiple files, if you select them one-by-one). I think we should log this issue for next semester and take another look with fresh eyes, but you're absolutely welcome to look into it too if you'd like!

const [anonymousUpload, setAnonymousUpload] = useState(false);
const dispatch = useDispatch();
const id = Number(useParams<TreeParams>().id);

const props: UploadProps = {
name: 'file',
multiple: true,
beforeUpload: async (file) => {
beforeUpload: (_, fileList) => {
console.log('before upload');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ Make sure to remove any console.log() calls before you merge! It's a tiny optimization for production, but we'd still like to get rid of them if we can (also our linter will throw a fit if it finds any console.log() calls 🤷)

@SurabhiKeesara SurabhiKeesara requested a review from huang0h April 17, 2024 14:52
huang0h
huang0h previously approved these changes Apr 17, 2024
@huang0h huang0h merged commit eb3feea into master Apr 18, 2024
4 of 5 checks passed
@huang0h huang0h deleted the SK.CL.upload-site-image branch April 18, 2024 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add site image uploading
2 participants