Skip to content

Commit

Permalink
Merge pull request #31 from openrice-canada/feat/photo
Browse files Browse the repository at this point in the history
feat: menu photo
  • Loading branch information
ttiimmothy authored Nov 23, 2023
2 parents eaf76f5 + 04d02c1 commit 5f2645c
Show file tree
Hide file tree
Showing 17 changed files with 481 additions and 80 deletions.
45 changes: 39 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@
"react-scripts": "5.0.1",
"react-select": "^5.7.7",
"typescript": "^4.9.5",
"uuid": "^9.0.1",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@types/google.maps": "^3.54.3",
"@types/react-datepicker": "^4.19.1",
"@types/uuid": "^9.0.7",
"tailwindcss": "^3.3.3"
},
"eslintConfig": {
Expand Down
14 changes: 12 additions & 2 deletions src/api/photo/PhotoType.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
export type Photo = {
photo_id: string;
export type ReviewPhoto = {
review_photo_id: string;
photo_category_id: string;
review_id: string;
restaurant_id?: string;
photo_url: string;
active: boolean;
created_at: string;
};

export type MenuPhoto = {
menu_photo_id: string;
photo_category_id: string;
review_id?: string;
restaurant_id: string;
photo_url: string;
active: boolean;
created_at: string;
};
21 changes: 18 additions & 3 deletions src/api/photo/photoApiIndex.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { AxiosApiClientBuilder } from "../axiosIndex";
import { Photo } from "./PhotoType";
import { MenuPhoto, ReviewPhoto } from "./PhotoType";

const apiClient = new AxiosApiClientBuilder()
.withResourceName("/photo")
.build();

export const getReviewPhotos = async (
restaurantID: string
): Promise<Photo[]> => {
): Promise<ReviewPhoto[]> => {
return apiClient.get("review", { params: { restaurantID } });
};

export const getMenuPhotos = async (restaurantID: string): Promise<Photo[]> => {
export const getMenuPhotos = async (
restaurantID: string
): Promise<MenuPhoto[]> => {
return apiClient.get("menu", { params: { restaurantID } });
};

export const createMenuPhoto = async (
imagePrefix: string,
restaurantID: string,
imageName: string,
photoCategory: string
): Promise<MenuPhoto> => {
return apiClient.post(
"",
{ imagePrefix, restaurantID, imageName },
{ params: { photoCategory } }
);
};
4 changes: 2 additions & 2 deletions src/components/utils/buttons/UploadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const UploadButton: React.FC<{
return (
<button
type="submit"
className="border-gray-700 h-full w-20 flex justify-center items-center rounded-md text-md px-11 py-2 border-2 hover:bg-gray-700 hover:text-white"
onClick={() => showUploadImageModal}
className="border-gray-700 h-full w-20 flex justify-center items-center rounded-md text-md px-11 py-2 border-1 hover:bg-gray-700 hover:text-white"
onClick={() => showUploadImageModal(true)}
>
upload
</button>
Expand Down
25 changes: 25 additions & 0 deletions src/components/utils/inputs/DateInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
interface DateInputProps {
label: string;
placeholder: string;
value: string | number;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
type?: React.HTMLInputTypeAttribute;
}

const DateInput = ({ label, placeholder, value, onChange }: DateInputProps) => {
return (
<div className="flex flex-col gap-1">
<label className="text-sm font-semibold">{label}</label>
<input
className="border border-gray-400 rounded-md p-2"
type="date"
placeholder={placeholder}
value={value}
onChange={onChange}
min={new Date().toISOString().split("T")[0]}
/>
</div>
);
};

export default DateInput;
6 changes: 3 additions & 3 deletions src/components/utils/inputs/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
type FileInputProps = {
label: string;
label?: string;
placeholder: string;
value?: string | number;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
Expand All @@ -16,9 +16,9 @@ const FileInput = ({
}: FileInputProps) => {
return (
<div className="flex flex-col gap-1">
<label className="text-sm font-semibold">{label}</label>
{label && <label className="text-sm font-semibold">{label}</label>}
<input
className={`border border-gray-400 rounded-md p-2 ${className}`}
className={className}
type={type}
placeholder={placeholder}
onChange={onChange}
Expand Down
9 changes: 5 additions & 4 deletions src/components/utils/modals/CreateReviewModal.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { useSelector } from "react-redux";
import { Controller, useForm } from "react-hook-form";
import { IoClose } from "react-icons/io5";
import { closeSnackbar, enqueueSnackbar } from "notistack";

import { IRootState } from "../../../store";
import { createReview } from "../../../api/review/reviewApiIndex";
import { TextareaInput } from "../inputs/TextareaInput";
import { uploadImage } from "../../../utils/uploadImageService";
import TextInput from "../inputs/TextInput";
import NumberInput from "../inputs/NumberInput";
import FileInput from "../inputs/FileInput";
import { uploadImage } from "../../../utils/uploadImageService";
import { useCallback } from "react";
import { createReview } from "../../../api/review/reviewApiIndex";
import DateInput from "../inputs/DateInput";

interface CreateReviewModalProps {
show: boolean;
Expand Down Expand Up @@ -187,7 +188,7 @@ const CreateReviewModal: React.FC<CreateReviewModalProps> = (
control={control}
name="visit_date"
render={({ field }) => (
<TextInput
<DateInput
value={field.value}
onChange={field.onChange}
label="Visit Date"
Expand Down
6 changes: 4 additions & 2 deletions src/components/utils/modals/PhotoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ const PhotoModal: React.FC<{
selectedImage: string;
closePopUp: () => void;
imageRef: React.MutableRefObject<HTMLDivElement | null>;
}> = ({ selectedImage, closePopUp, imageRef }) => {
imageID: string;
}> = ({ selectedImage, closePopUp, imageRef, imageID }) => {
return (
<div className="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-black bg-opacity-70">
<div className="bg-white rounded-xl" ref={imageRef}>
<div className="flex items-center justify-end p-2 px-4 border-b border-solid border-slate-200 rounded-t">
<div className="flex items-center justify-between p-2 px-4 border-b border-solid border-slate-200 rounded-t">
<h3 className="text-sm">{imageID}</h3>
<button
className="p-2 ml-auto text-black float-right text-3xl leading-none font-semibold outline-none rounded-full hover:bg-gray-200 focus:outline-none"
onClick={closePopUp}
Expand Down
94 changes: 94 additions & 0 deletions src/components/utils/modals/UploadImageModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { v4 as uuid } from "uuid";
import { closeSnackbar, enqueueSnackbar } from "notistack";
import { IoClose } from "react-icons/io5";

import { AppDispatch, IRootState } from "../../../store";
import { createMenuPhotoThunk } from "../../../redux/photo/photoSlice";
import { uploadImage } from "../../../utils/uploadImageService";
import FileInput from "../inputs/FileInput";

interface UploadImageModalProps {
show: boolean;
setShow: React.Dispatch<React.SetStateAction<boolean>>;
Expand All @@ -11,7 +21,70 @@ const UploadImageModal: React.FC<UploadImageModalProps> = ({
show,
setShow,
modalRef,
restaurant_id,
}) => {
const navigate = useNavigate();
const [image, setImage] = useState<File | null>(null);

const dispatch = useDispatch<AppDispatch>();
const user = useSelector((state: IRootState) => state.auth.currentUser);

const fileTypeToExtension: Record<string, string> = {
"image/jpeg": "jpg",
"image/png": "png",
"application/pdf": "pdf",
};

const uploadMenuPhoto = async () => {
let imageName;
if (user?.user_id) {
if (image && image?.type) {
const randomID = uuid();
imageName = `${randomID}.${fileTypeToExtension[image?.type]}`;

dispatch(
createMenuPhotoThunk({
imagePrefix: process.env.REACT_APP_IMAGE_PREFIX as string,
restaurantID: restaurant_id as string,
imageName,
photoCategory: "Menu",
})
);
await uploadImage(
image as File,
restaurant_id as string,
"menus",
"",
imageName
);

enqueueSnackbar("Menu photo is added successfully", {
variant: "success",
});
setShow(false);
setTimeout(() => {
navigate(`/restaurant/id/${restaurant_id}`);
navigate(0);
}, 1000);

setTimeout(() => {
closeSnackbar();
}, 2000);
}
} else {
enqueueSnackbar("You haven't login yet", { variant: "error" });
setShow(false);
setTimeout(() => {
navigate(`/restaurant/id/${restaurant_id}`);
navigate(0);
}, 1000);

setTimeout(() => {
closeSnackbar();
}, 2000);
}
};

return show ? (
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
Expand All @@ -31,6 +104,27 @@ const UploadImageModal: React.FC<UploadImageModalProps> = ({
</span>
</button>
</div>
<div className="p-4 flex flex-col justify-center">
<FileInput
onChange={(e) => {
if (e.target.files) {
const selectedFile = e.target.files[0];
setImage(selectedFile);
}
}}
type="file"
className="form-control"
placeholder=""
/>
<div className="w-full flex justify-center">
<button
className="border-slate-600 border-1 hover:bg-slate-600 hover:text-white font-bold py-1 px-4 mt-4 rounded w-[40%]"
onClick={uploadMenuPhoto}
>
Submit
</button>
</div>
</div>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 5f2645c

Please sign in to comment.