From 191bf2809b1722a534c8a4055958308395993443 Mon Sep 17 00:00:00 2001 From: ttiimmothy Date: Wed, 22 Nov 2023 05:15:01 -0500 Subject: [PATCH] feat: photo --- src/api/auth/authApiIndex.ts | 8 +- src/api/auth/authType.ts | 2 +- src/api/photo/PhotoType.ts | 9 + src/api/photo/photoApiIndex.ts | 16 + src/api/restaurant/restaurantApiIndex.ts | 2 +- .../restaurantDish/restaurantDishApiIndex.ts | 4 +- .../restaurantPaymentMethodApiIndex.ts | 4 +- src/api/review/ReviewType.ts | 2 +- src/api/review/reviewApiIndex.ts | 17 +- src/components/utils/cards/RestaurantCard.tsx | 2 +- src/components/utils/cards/ReviewCard.tsx | 14 +- ...dReviewModal.tsx => CreateReviewModal.tsx} | 129 ++++--- src/pages/map/MapPage.tsx | 1 - src/pages/restaurant/CreateRestaurantPage.tsx | 2 +- .../restaurant/RestaurantOverviewPage.tsx | 353 ++++++++++-------- src/pages/review/ReviewPage.tsx | 23 +- src/redux/photo/photoSlice.ts | 62 +++ .../reviewsSlice.ts => review/reviewSlice.ts} | 31 +- src/router.tsx | 4 +- src/store.ts | 9 +- 20 files changed, 432 insertions(+), 262 deletions(-) create mode 100644 src/api/photo/PhotoType.ts create mode 100644 src/api/photo/photoApiIndex.ts rename src/components/utils/modals/{AddReviewModal.tsx => CreateReviewModal.tsx} (71%) create mode 100644 src/redux/photo/photoSlice.ts rename src/redux/{reviews/reviewsSlice.ts => review/reviewSlice.ts} (69%) diff --git a/src/api/auth/authApiIndex.ts b/src/api/auth/authApiIndex.ts index 67671a0..656bd99 100644 --- a/src/api/auth/authApiIndex.ts +++ b/src/api/auth/authApiIndex.ts @@ -1,18 +1,16 @@ import { AxiosApiClientBuilder } from "../axiosIndex"; -import { AuthType, AuthenticateResponse } from "./authType"; +import { Auth, AuthenticateResponse } from "./authType"; const apiClient = new AxiosApiClientBuilder() .withResourceName("/auth/user") .withCredentials(true) .build(); -export const register = async ( - user: AuthType -): Promise => { +export const register = async (user: Auth): Promise => { return apiClient.post("/register", user); }; -export const login = async (user: AuthType): Promise => { +export const login = async (user: Auth): Promise => { return apiClient.post("/login", user); }; diff --git a/src/api/auth/authType.ts b/src/api/auth/authType.ts index 50a9ded..d12a9b1 100644 --- a/src/api/auth/authType.ts +++ b/src/api/auth/authType.ts @@ -1,6 +1,6 @@ import { CurrentLoginUserInfo } from "../../redux/auth/authSlice"; -export type AuthType = { +export type Auth = { username?: string; email?: string; password: string; diff --git a/src/api/photo/PhotoType.ts b/src/api/photo/PhotoType.ts new file mode 100644 index 0000000..973f4cf --- /dev/null +++ b/src/api/photo/PhotoType.ts @@ -0,0 +1,9 @@ +export type Photo = { + photo_id: string; + photo_category_id: string; + review_id: string; + restaurant_id?: string; + photo_url: string; + active: boolean; + created_at: string; +}; diff --git a/src/api/photo/photoApiIndex.ts b/src/api/photo/photoApiIndex.ts new file mode 100644 index 0000000..17c4917 --- /dev/null +++ b/src/api/photo/photoApiIndex.ts @@ -0,0 +1,16 @@ +import { AxiosApiClientBuilder } from "../axiosIndex"; +import { Photo } from "./PhotoType"; + +const apiClient = new AxiosApiClientBuilder() + .withResourceName("/photo") + .build(); + +export const getReviewPhotos = async ( + restaurantID: string +): Promise => { + return apiClient.get("review", { params: { restaurantID } }); +}; + +export const getMenuPhotos = async (restaurantID: string): Promise => { + return apiClient.get("menu", { params: { restaurantID } }); +}; diff --git a/src/api/restaurant/restaurantApiIndex.ts b/src/api/restaurant/restaurantApiIndex.ts index 462665b..5a33a5a 100644 --- a/src/api/restaurant/restaurantApiIndex.ts +++ b/src/api/restaurant/restaurantApiIndex.ts @@ -18,7 +18,7 @@ export const getRestaurants = async ( export const getRestaurantDetail = async ( restaurantId: string ): Promise => { - return apiClient.get(restaurantId); + return apiClient.get(`id/${restaurantId}`); }; export const createRestaurant = async ( diff --git a/src/api/restaurantDish/restaurantDishApiIndex.ts b/src/api/restaurantDish/restaurantDishApiIndex.ts index abd10c1..941be10 100644 --- a/src/api/restaurantDish/restaurantDishApiIndex.ts +++ b/src/api/restaurantDish/restaurantDishApiIndex.ts @@ -2,11 +2,11 @@ import { AxiosApiClientBuilder } from "../axiosIndex"; import { RestaurantDish } from "./RestaurantDishType"; const apiClient = new AxiosApiClientBuilder() - .withResourceName("/restaurant-dish") + .withResourceName("/restaurant/dish") .build(); export const createRestaurantDish = async ( restaurantDish: RestaurantDish ): Promise => { - return apiClient.post("/restaurant-dish", restaurantDish); + return apiClient.post("", restaurantDish); }; diff --git a/src/api/restaurantPaymentMethod/restaurantPaymentMethodApiIndex.ts b/src/api/restaurantPaymentMethod/restaurantPaymentMethodApiIndex.ts index a1de655..17f83ce 100644 --- a/src/api/restaurantPaymentMethod/restaurantPaymentMethodApiIndex.ts +++ b/src/api/restaurantPaymentMethod/restaurantPaymentMethodApiIndex.ts @@ -2,11 +2,11 @@ import { AxiosApiClientBuilder } from "../axiosIndex"; import { RestaurantPaymentMethod } from "./RestaurantPaymentMethodType"; const apiClient = new AxiosApiClientBuilder() - .withResourceName("/restaurant-payment") + .withResourceName("/restaurant/payment/method") .build(); export const createRestaurantPaymentMethod = async ( restaurantPaymentMethod: RestaurantPaymentMethod ): Promise => { - return apiClient.post("/restaurant-payment-method", restaurantPaymentMethod); + return apiClient.post("", restaurantPaymentMethod); }; diff --git a/src/api/review/ReviewType.ts b/src/api/review/ReviewType.ts index 939bba1..1a1698a 100644 --- a/src/api/review/ReviewType.ts +++ b/src/api/review/ReviewType.ts @@ -15,7 +15,7 @@ export type Review = { modified_at: string; }; -export type CreateReviewRequest = { +export type CreateReviewDto = { user_id: string; restaurant_id: string; title: string; diff --git a/src/api/review/reviewApiIndex.ts b/src/api/review/reviewApiIndex.ts index d3f2bfb..f31da33 100644 --- a/src/api/review/reviewApiIndex.ts +++ b/src/api/review/reviewApiIndex.ts @@ -1,5 +1,5 @@ import { AxiosApiClientBuilder } from "../axiosIndex"; -import { CreateReviewRequest, Review } from "./ReviewType"; +import { CreateReviewDto, Review } from "./ReviewType"; const apiClient = new AxiosApiClientBuilder() .withResourceName("/review") @@ -16,11 +16,18 @@ export const getReviewsByRestaurantID = async ( }; export const createReview = async ( - input: CreateReviewRequest + createReviewDto: CreateReviewDto, + imagePrefix: string, + restaurantID: string, + photoCategory: string ): Promise => { - return apiClient.post("", input); + return apiClient.post( + "", + { createReviewDto, imagePrefix, restaurantID }, + { params: { photoCategory } } + ); }; -export const getReview = async (reviewId: string): Promise => { - return apiClient.get(reviewId); +export const getReview = async (reviewID: string): Promise => { + return apiClient.get(`id/${reviewID}`); }; diff --git a/src/components/utils/cards/RestaurantCard.tsx b/src/components/utils/cards/RestaurantCard.tsx index 50be326..360d1e0 100644 --- a/src/components/utils/cards/RestaurantCard.tsx +++ b/src/components/utils/cards/RestaurantCard.tsx @@ -17,7 +17,7 @@ const RestaurantCard: React.FC = (props: Restaurant) => { ); return (
diff --git a/src/components/utils/cards/ReviewCard.tsx b/src/components/utils/cards/ReviewCard.tsx index 629fabf..35369e0 100644 --- a/src/components/utils/cards/ReviewCard.tsx +++ b/src/components/utils/cards/ReviewCard.tsx @@ -20,7 +20,7 @@ const ReviewRow = ({ text, icon }: { text: string; icon: React.ReactNode }) => ( const ReviewCard: React.FC = (props: Review) => { return (
@@ -33,11 +33,13 @@ const ReviewCard: React.FC = (props: Review) => { />
{}
- {Array.from({ length: props.rating }).map((_, index) => ( - - {} - - ))} +
+ {Array.from({ length: props.rating }).map((_, index) => ( + + {} + + ))} +
>; +interface CreateReviewModalProps { + show: boolean; + setShow: React.Dispatch>; formRef: React.MutableRefObject; restaurant_id?: string; -}; +} export type ReviewForm = { rating: number; @@ -29,8 +30,8 @@ export type ReviewForm = { photo?: any; }; -const AddReviewModal: React.FC = ( - props: AddReviewModalProps +const CreateReviewModal: React.FC = ( + props: CreateReviewModalProps ) => { const navigate = useNavigate(); const { control, handleSubmit } = useForm({ @@ -44,60 +45,64 @@ const AddReviewModal: React.FC = ( } as ReviewForm, }); - const dispatch = useDispatch(); const user = useSelector((state: IRootState) => state.auth.currentUser); - const reviewID = useSelector( - (state: IRootState) => state.review.review?.review_id - ); - - const addReview = async (review: ReviewForm) => { - if (user?.user_id) { - dispatch( - createReviewThunk({ - title: review.title, - content: review.content, - spending: review.spending, - rating: review.rating, - restaurant_id: props?.restaurant_id as string, - user_id: user?.user_id, - visit_date: new Date(review.visit_date), - }) - ); - if (review.photo) { - await uploadImage( - review.photo, - props?.restaurant_id as string, - "reviews", - reviewID + const createNewReview = useCallback( + async (review: ReviewForm) => { + if (user?.user_id) { + const res = await createReview( + { + title: review.title, + content: review.content, + spending: review.spending, + rating: review.rating, + restaurant_id: props?.restaurant_id as string, + user_id: user?.user_id, + visit_date: new Date(review.visit_date), + }, + process.env.REACT_APP_IMAGE_PREFIX as string, + props.restaurant_id as string, + "Review" ); - } - enqueueSnackbar("Review added successfully", { variant: "success" }); - setTimeout(() => { - navigate(`/restaurant/${props?.restaurant_id}`); - navigate(0); - }, 1000); + if (review.photo) { + await uploadImage( + review.photo, + props.restaurant_id as string, + "photos", + res?.review_id + ); + } - setTimeout(() => { - closeSnackbar(); - }, 2000); - } else { - enqueueSnackbar("You haven't login yet", { variant: "error" }); - setTimeout(() => { - navigate(`/restaurant/${props?.restaurant_id}`); - navigate(0); - }, 1000); + enqueueSnackbar("Review and Review photo is added successfully", { + variant: "success", + }); + props.setShow(false); + setTimeout(() => { + navigate(`/restaurant/id/${props?.restaurant_id}`); + navigate(0); + }, 1000); - setTimeout(() => { - closeSnackbar(); - }, 2000); - } - }; + setTimeout(() => { + closeSnackbar(); + }, 2000); + } else { + enqueueSnackbar("You haven't login yet", { variant: "error" }); + props.setShow(false); + setTimeout(() => { + navigate(`/restaurant/id/${props?.restaurant_id}`); + navigate(0); + }, 1000); - if (!props.isShown) return null; + setTimeout(() => { + closeSnackbar(); + }, 2000); + } + }, + [navigate, user?.user_id, props] + ); - return ( + return props.show ? (
@@ -106,10 +111,10 @@ const AddReviewModal: React.FC = ( ref={props.formRef} >
-

Add Review

+

Create New Review

+ ) : ( + <> ); }; -export default AddReviewModal; +export default CreateReviewModal; diff --git a/src/pages/map/MapPage.tsx b/src/pages/map/MapPage.tsx index 6eeb243..3ca7ec6 100644 --- a/src/pages/map/MapPage.tsx +++ b/src/pages/map/MapPage.tsx @@ -2,7 +2,6 @@ import { useEffect } from "react"; import { getRestaurantsByQueryThunk } from "../../redux/restaurant/restaurantSlice"; import { useDispatch, useSelector } from "react-redux"; import { AppDispatch, IRootState } from "../../store"; - import MapComponent from "../../components/map/MapComponent"; const MapPage = () => { diff --git a/src/pages/restaurant/CreateRestaurantPage.tsx b/src/pages/restaurant/CreateRestaurantPage.tsx index d21f118..ecae7b3 100644 --- a/src/pages/restaurant/CreateRestaurantPage.tsx +++ b/src/pages/restaurant/CreateRestaurantPage.tsx @@ -104,7 +104,7 @@ const CreateRestaurantPage: React.FC = () => { enqueueSnackbar("Restaurant added successfully!", { variant: "success" }); setTimeout(() => { - navigate(`/restaurant/${restaurantID}`); + navigate(`/restaurant/id/${restaurantID}`); navigate(0); }, 1000); diff --git a/src/pages/restaurant/RestaurantOverviewPage.tsx b/src/pages/restaurant/RestaurantOverviewPage.tsx index 5935c91..96b3666 100644 --- a/src/pages/restaurant/RestaurantOverviewPage.tsx +++ b/src/pages/restaurant/RestaurantOverviewPage.tsx @@ -1,15 +1,21 @@ import { useEffect, useRef, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; -import { IoChatbubbleOutline } from "react-icons/io5"; +import { useParams } from "react-router-dom"; import { useDispatch, useSelector } from "react-redux"; +import { IoChatbubbleOutline, IoStar } from "react-icons/io5"; + import { AppDispatch, IRootState } from "../../store"; import { getRestaurantThunk } from "../../redux/restaurant/restaurantSlice"; -import { getReviewsThunk } from "../../redux/reviews/reviewsSlice"; - +import { getReviewsThunk } from "../../redux/review/reviewSlice"; +import { + getMenuPhotosThunk, + getReviewPhotosThunk, + updateMenuPhotos, + updateReviewPhotos, +} from "../../redux/photo/photoSlice"; import useOnClickOutside from "../../components/hooks/useOnClickOutside"; import RestaurantOverviewButton from "../../components/utils/buttons/RestaurantOverviewButton"; import ReviewCard from "../../components/utils/cards/ReviewCard"; -import AddReviewModal from "../../components/utils/modals/AddReviewModal"; +import CreateReviewModal from "../../components/utils/modals/CreateReviewModal"; import RestaurantDetailSkeletonLoader from "../../components/skeletonLoader/RestaurantDetailSkeletonLoader"; import PhotoModal from "../../components/utils/modals/PhotoModal"; import ErrorPage from "../error/ErrorPage"; @@ -23,14 +29,12 @@ function isUUID(id: string) { const RestaurantOverviewPage: React.FC = () => { const { id } = useParams(); - const navigate = useNavigate(); const [page, setPage] = useState("Reviews"); - const [isShownAddReviewModal, setIsShownAddReviewModal] = useState(false); - const [photos, setPhotos] = useState<{ id: string; src: string }[]>([]); - const [menus, setMenus] = useState<{ id: string; src: string }[]>([]); + const [shownCreateReviewModal, setShowCreateReviewModal] = useState(false); const [popUpOpen, setPopUpOpen] = useState(false); const [selectedImage, setSelectedImage] = useState(""); + const [loading, setLoading] = useState(true); const imageRef = useRef(null); const formRef = useRef(null); @@ -40,6 +44,10 @@ const RestaurantOverviewPage: React.FC = () => { (state: IRootState) => state.restaurant.restaurant ); const reviews = useSelector((state: IRootState) => state.review.reviews); + const reviewPhotos = useSelector( + (state: IRootState) => state.photo.reviewPhotos + ); + const menuPhotos = useSelector((state: IRootState) => state.photo.menuPhotos); useEffect(() => { const fetchRestaurantDetail = async () => { @@ -52,16 +60,24 @@ const RestaurantOverviewPage: React.FC = () => { dispatch(getReviewsThunk(id)); }; + const fetchReviewPhotos = async () => { + if (!id || !isUUID(id)) return; + dispatch(getReviewPhotosThunk(id)); + }; + + const fetchMenuPhotos = async () => { + if (!id || !isUUID(id)) return; + dispatch(getMenuPhotosThunk(id)); + }; + + setLoading(true); fetchRestaurantDetail(); fetchRestaurantReview(); + fetchReviewPhotos(); + fetchMenuPhotos(); + setLoading(false); }, [id, dispatch]); - useEffect(() => { - if (!id || !isUUID(id)) { - navigate("error"); - } - }, [id, navigate]); - const openPopUp = (image: string) => { setSelectedImage(image); setPopUpOpen(true); @@ -70,62 +86,79 @@ const RestaurantOverviewPage: React.FC = () => { setPopUpOpen(false); }; useOnClickOutside(imageRef, () => setPopUpOpen(false)); - useOnClickOutside(formRef, () => setIsShownAddReviewModal(false)); + useOnClickOutside(formRef, () => setShowCreateReviewModal(false)); const loadDefaultImage = (type: string, id: string) => { - if (type === "photo") { - setPhotos( - photos.map((photo) => - photo.id === id - ? { id, src: `${process.env.PUBLIC_URL}/error.svg` } - : photo + if (type === "review") { + dispatch( + updateReviewPhotos( + reviewPhotos.map((reviewPhoto) => + reviewPhoto.photo_id === id + ? { + ...reviewPhoto, + photo_url: `${process.env.PUBLIC_URL}/error.svg`, + } + : reviewPhoto + ) ) ); } else if (type === "menu") { - setMenus( - menus.map((menu) => - menu.id === id - ? { id, src: `${process.env.PUBLIC_URL}/error.svg` } - : menu + dispatch( + updateMenuPhotos( + menuPhotos.map((menuPhoto) => + menuPhoto.photo_id === id + ? { + ...menuPhoto, + photo_url: `${process.env.PUBLIC_URL}/error.svg`, + } + : menuPhoto + ) ) ); } }; - const buttons = ["Reviews", "Photos", "Menus"]; - if (!restaurantDetail) return null; - return !id || !isUUID(id) ? ( + return !restaurantDetail && loading ? ( + + ) : !restaurantDetail && !loading ? ( ) : ( - <> - -
-
-
-
- {restaurantDetail && ( - - )} -
- {!restaurantDetail ? ( - - ) : ( + restaurantDetail && ( + <> + +
+
+
+
+ {restaurantDetail && ( + + )} +

{restaurantDetail.name}

{restaurantDetail.averageRating && ( -
+
rating
-
{restaurantDetail.averageRating}
+
{restaurantDetail.averageRating.toPrecision(3)}
+
+ {Array.from({ + length: Math.round(restaurantDetail.averageRating), + }).map((_, index) => ( + + {} + + ))} +
)}
@@ -133,117 +166,121 @@ const RestaurantOverviewPage: React.FC = () => {
{restaurantDetail.intro}
- )} +
-
-
-
- {buttons.map((button, index) => ( - - ))} +
+
+ {buttons.map((button, index) => ( + + ))} +
-
- {page === "Reviews" && ( - <> -
-

Reviews

-
- + {page === "Reviews" && ( + <> +
+

Reviews

+
+ +
-
- {reviews.length === 0 &&
No review in this restaurant
} - {reviews.length > 0 && ( -
- {reviews.map((review) => ( - - ))} + {reviews.length === 0 &&
No review in this restaurant
} + {reviews.length > 0 && ( +
+ {reviews.map((review) => ( + + ))} +
+ )} + + )} + {page === "Photos" && ( + <> +
+

Photos

- )} - - )} - {page === "Photos" && ( - <> -
-

Photos

-
- {photos.length === 0 &&
No photos in this restaurant
} - {photos.length > 0 && ( -
- {photos.map((photo, index) => ( -
openPopUp(photo.src)} - key={`photo${index}`} - > - loadDefaultImage("photo", photo.id)} + {reviewPhotos.length === 0 && ( +
No review photos in this restaurant
+ )} + {reviewPhotos.length > 0 && ( +
+ {reviewPhotos.map((review, index) => ( +
openPopUp(review.photo_url)} + key={`review ${index}`} + > + + loadDefaultImage("review", review.photo_id) + } + /> +
+ ))} + {popUpOpen && ( + -
- ))} - {popUpOpen && ( - - )} + )} +
+ )} + + )} + {page === "Menus" && ( + <> +
+

Menus

+
- )} - - )} - {page === "Menus" && ( - <> -
-

Menus

- -
- {menus.length === 0 && ( -
No menu photos are provided for this restaurant
- )} - {menus.length > 0 && ( -
- {menus.map((menu, index) => ( -
openPopUp(menu.src)} - key={`menu${index}`} - > - loadDefaultImage("menu", menu.id)} + {menuPhotos.length === 0 && ( +
No menu photos are provided for this restaurant
+ )} + {menuPhotos.length > 0 && ( +
+ {menuPhotos.map((menu, index) => ( +
openPopUp(menu.photo_url)} + key={`menu ${index}`} + > + loadDefaultImage("menu", menu.photo_id)} + /> +
+ ))} + {popUpOpen && ( + -
- ))} - {popUpOpen && ( - - )} -
- )} - - )} -
- + )} +
+ )} + + )} +
+ + ) ); }; diff --git a/src/pages/review/ReviewPage.tsx b/src/pages/review/ReviewPage.tsx index df97332..b01df31 100644 --- a/src/pages/review/ReviewPage.tsx +++ b/src/pages/review/ReviewPage.tsx @@ -10,7 +10,7 @@ import { import { format } from "date-fns"; import { useDispatch, useSelector } from "react-redux"; import { AppDispatch, IRootState } from "../../store"; -import { getReviewThunk } from "../../redux/reviews/reviewsSlice"; +import { getReviewThunk } from "../../redux/review/reviewSlice"; function isUUID(id: string) { const uuidPattern = @@ -33,6 +33,9 @@ const ReviewPage: React.FC = () => { const restaurant = useSelector( (state: IRootState) => state.restaurant.restaurant ); + const reviewPhotos = useSelector( + (state: IRootState) => state.photo.reviewPhotos + ); useEffect(() => { const fetchReview = async () => { @@ -54,8 +57,8 @@ const ReviewPage: React.FC = () => { {review?.restaurantName}

-
-
+
+
{review && (

{review.title} @@ -72,11 +75,23 @@ const ReviewPage: React.FC = () => { } icon={} /> +
+
Photos
+ reviewPhoto.review_id === id + )[0].photo_url + } + alt="review photo" + className="object-cover h-[100%] w-auto rounded-md" + /> +

)}
-
+
{review && ( <>
User
diff --git a/src/redux/photo/photoSlice.ts b/src/redux/photo/photoSlice.ts new file mode 100644 index 0000000..7a00435 --- /dev/null +++ b/src/redux/photo/photoSlice.ts @@ -0,0 +1,62 @@ +import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { Photo } from "../../api/photo/PhotoType"; +import { getMenuPhotos, getReviewPhotos } from "../../api/photo/photoApiIndex"; + +export interface IPhotoState { + reviewPhotos: Photo[]; + menuPhotos: Photo[]; +} + +const initialState: IPhotoState = { + reviewPhotos: [], + menuPhotos: [], +}; + +export const getReviewPhotosThunk = createAsyncThunk( + "photo/review", + async (id: string) => { + const response = await getReviewPhotos(id); + return response; + } +); + +export const getMenuPhotosThunk = createAsyncThunk( + "photo/menu", + async (id: string) => { + const response = await getMenuPhotos(id); + return response; + } +); + +const photoReducer = createSlice({ + name: "photo", + initialState, + reducers: { + updateReviewPhotos: ( + state: IPhotoState, + action: PayloadAction + ) => { + state.reviewPhotos = action.payload; + }, + + updateMenuPhotos: (state: IPhotoState, action: PayloadAction) => { + state.reviewPhotos = action.payload; + }, + }, + extraReducers: (builder) => { + builder.addCase(getReviewPhotosThunk.fulfilled, (state, action) => { + if (action.payload) { + state.reviewPhotos = action.payload; + } + }); + + builder.addCase(getMenuPhotosThunk.fulfilled, (state, action) => { + if (action.payload) { + state.menuPhotos = action.payload; + } + }); + }, +}); + +export const { updateReviewPhotos, updateMenuPhotos } = photoReducer.actions; +export default photoReducer.reducer; diff --git a/src/redux/reviews/reviewsSlice.ts b/src/redux/review/reviewSlice.ts similarity index 69% rename from src/redux/reviews/reviewsSlice.ts rename to src/redux/review/reviewSlice.ts index cf17d42..d9623e7 100644 --- a/src/redux/reviews/reviewsSlice.ts +++ b/src/redux/review/reviewSlice.ts @@ -1,17 +1,17 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import { CreateReviewRequest, Review } from "../../api/review/ReviewType"; +import { CreateReviewDto, Review } from "../../api/review/ReviewType"; import { getReview, getReviewsByRestaurantID, createReview, } from "../../api/review/reviewApiIndex"; -export interface IReviewsState { +export interface IReviewState { reviews: Review[]; review: Review | null; } -const initialState: IReviewsState = { +const initialState: IReviewState = { reviews: [], review: null, }; @@ -34,14 +34,29 @@ export const getReviewThunk = createAsyncThunk( export const createReviewThunk = createAsyncThunk( "review/create", - async (review: CreateReviewRequest) => { - const response = await createReview(review); + async ({ + review, + imagePrefix, + restaurantID, + photoCategory, + }: { + review: CreateReviewDto; + imagePrefix: string; + restaurantID: string; + photoCategory: string; + }) => { + const response = await createReview( + review, + imagePrefix, + restaurantID, + photoCategory + ); return response; } ); -const reviewsReducer = createSlice({ - name: "reviews", +const reviewReducer = createSlice({ + name: "review", initialState, reducers: {}, extraReducers: (builder) => { @@ -65,4 +80,4 @@ const reviewsReducer = createSlice({ }, }); -export default reviewsReducer.reducer; +export default reviewReducer.reducer; diff --git a/src/router.tsx b/src/router.tsx index baf46a0..66b6399 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -32,7 +32,7 @@ const router = createBrowserRouter( element: , }, { - path: "/review/:id", + path: "/review/id/:id", element: , }, { @@ -48,7 +48,7 @@ const router = createBrowserRouter( element: , children: [ { - path: ":id", + path: "id/:id", element: , }, { diff --git a/src/store.ts b/src/store.ts index e42bd08..1863d86 100644 --- a/src/store.ts +++ b/src/store.ts @@ -3,7 +3,7 @@ import authReducer, { IAuthState } from "./redux/auth/authSlice"; import restaurantReducer, { IRestaurantState, } from "./redux/restaurant/restaurantSlice"; -import reviewsReducer, { IReviewsState } from "./redux/reviews/reviewsSlice"; +import reviewReducer, { IReviewState } from "./redux/review/reviewSlice"; import dishReducer, { IDishState } from "./redux/dish/dishSlice"; import districtReducer, { IDistrictState, @@ -17,27 +17,30 @@ import restaurantDishReducer, { import restaurantPaymentMethodReducer, { IRestaurantPaymentMethodState, } from "./redux/restaurantPaymentMethod/restaurantPaymentMethodSlice"; +import photoReducer, { IPhotoState } from "./redux/photo/photoSlice"; export interface IRootState { auth: IAuthState; restaurant: IRestaurantState; - review: IReviewsState; + review: IReviewState; dish: IDishState; district: IDistrictState; paymentMethod: IPaymentMethodState; restaurantDish: IRestaurantDishState; restaurantPaymentMethod: IRestaurantPaymentMethodState; + photo: IPhotoState; } const reducer = combineReducers({ auth: authReducer, restaurant: restaurantReducer, - review: reviewsReducer, + review: reviewReducer, dish: dishReducer, district: districtReducer, paymentMethod: paymentMethodReducer, restaurantDish: restaurantDishReducer, restaurantPaymentMethod: restaurantPaymentMethodReducer, + photo: photoReducer, }); export const store = configureStore({