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

feat: photo #28

Merged
merged 1 commit into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/api/auth/authApiIndex.ts
Original file line number Diff line number Diff line change
@@ -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<AuthenticateResponse> => {
export const register = async (user: Auth): Promise<AuthenticateResponse> => {
return apiClient.post("/register", user);
};

export const login = async (user: AuthType): Promise<AuthenticateResponse> => {
export const login = async (user: Auth): Promise<AuthenticateResponse> => {
return apiClient.post("/login", user);
};

Expand Down
2 changes: 1 addition & 1 deletion src/api/auth/authType.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CurrentLoginUserInfo } from "../../redux/auth/authSlice";

export type AuthType = {
export type Auth = {
username?: string;
email?: string;
password: string;
Expand Down
9 changes: 9 additions & 0 deletions src/api/photo/PhotoType.ts
Original file line number Diff line number Diff line change
@@ -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;
};
16 changes: 16 additions & 0 deletions src/api/photo/photoApiIndex.ts
Original file line number Diff line number Diff line change
@@ -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<Photo[]> => {
return apiClient.get("review", { params: { restaurantID } });
};

export const getMenuPhotos = async (restaurantID: string): Promise<Photo[]> => {
return apiClient.get("menu", { params: { restaurantID } });
};
2 changes: 1 addition & 1 deletion src/api/restaurant/restaurantApiIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const getRestaurants = async (
export const getRestaurantDetail = async (
restaurantId: string
): Promise<Restaurant> => {
return apiClient.get(restaurantId);
return apiClient.get(`id/${restaurantId}`);
};

export const createRestaurant = async (
Expand Down
4 changes: 2 additions & 2 deletions src/api/restaurantDish/restaurantDishApiIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<RestaurantDish> => {
return apiClient.post("/restaurant-dish", restaurantDish);
return apiClient.post("", restaurantDish);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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<RestaurantPaymentMethod> => {
return apiClient.post("/restaurant-payment-method", restaurantPaymentMethod);
return apiClient.post("", restaurantPaymentMethod);
};
2 changes: 1 addition & 1 deletion src/api/review/ReviewType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type Review = {
modified_at: string;
};

export type CreateReviewRequest = {
export type CreateReviewDto = {
user_id: string;
restaurant_id: string;
title: string;
Expand Down
17 changes: 12 additions & 5 deletions src/api/review/reviewApiIndex.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AxiosApiClientBuilder } from "../axiosIndex";
import { CreateReviewRequest, Review } from "./ReviewType";
import { CreateReviewDto, Review } from "./ReviewType";

const apiClient = new AxiosApiClientBuilder()
.withResourceName("/review")
Expand All @@ -16,11 +16,18 @@ export const getReviewsByRestaurantID = async (
};

export const createReview = async (
input: CreateReviewRequest
createReviewDto: CreateReviewDto,
imagePrefix: string,
restaurantID: string,
photoCategory: string
): Promise<Review> => {
return apiClient.post("", input);
return apiClient.post(
"",
{ createReviewDto, imagePrefix, restaurantID },
{ params: { photoCategory } }
);
};

export const getReview = async (reviewId: string): Promise<Review> => {
return apiClient.get(reviewId);
export const getReview = async (reviewID: string): Promise<Review> => {
return apiClient.get(`id/${reviewID}`);
};
2 changes: 1 addition & 1 deletion src/components/utils/cards/RestaurantCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const RestaurantCard: React.FC<Restaurant> = (props: Restaurant) => {
);
return (
<Link
to={`/restaurant/${props.restaurant_id}`}
to={`/restaurant/id/${props.restaurant_id}`}
className="rounded-md shadow-lg hover:bg-slate-200"
>
<div className="w-full h-48 overflow-hidden">
Expand Down
14 changes: 8 additions & 6 deletions src/components/utils/cards/ReviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const ReviewRow = ({ text, icon }: { text: string; icon: React.ReactNode }) => (
const ReviewCard: React.FC<Review> = (props: Review) => {
return (
<Link
to={`/review/${props.review_id}`}
to={`/review/id/${props.review_id}`}
className="rounded-md shadow-lg hover:bg-slate-200"
>
<div className="flex justify-between">
Expand All @@ -33,11 +33,13 @@ const ReviewCard: React.FC<Review> = (props: Review) => {
/>
<div className="flex gap-2 items-start">
<div>{<IoThumbsUpSharp />}</div>
{Array.from({ length: props.rating }).map((_, index) => (
<span className="text-yellow-400" key={index}>
{<IoStar />}
</span>
))}
<div className="flex gap-1">
{Array.from({ length: props.rating }).map((_, index) => (
<span className="text-yellow-400" key={index}>
{<IoStar />}
</span>
))}
</div>
</div>
<ReviewRow
text={
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
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 { useNavigate } from "react-router-dom";

import { IRootState } from "../../../store";
import { TextareaInput } from "../inputs/TextareaInput";
import { uploadImage } from "../../../utils/imageService";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, IRootState } from "../../../store";
import TextInput from "../inputs/TextInput";
import NumberInput from "../inputs/NumberInput";
import FileInput from "../inputs/FileInput";
import { createReviewThunk } from "../../../redux/reviews/reviewsSlice";
import { uploadImage } from "../../../utils/imageService";
import { useCallback } from "react";
import { createReview } from "../../../api/review/reviewApiIndex";

type AddReviewModalProps = {
isShown: boolean;
setIsShown: React.Dispatch<React.SetStateAction<boolean>>;
interface CreateReviewModalProps {
show: boolean;
setShow: React.Dispatch<React.SetStateAction<boolean>>;
formRef: React.MutableRefObject<HTMLDivElement | null>;
restaurant_id?: string;
};
}

export type ReviewForm = {
rating: number;
Expand All @@ -29,8 +30,8 @@ export type ReviewForm = {
photo?: any;
};

const AddReviewModal: React.FC<AddReviewModalProps> = (
props: AddReviewModalProps
const CreateReviewModal: React.FC<CreateReviewModalProps> = (
props: CreateReviewModalProps
) => {
const navigate = useNavigate();
const { control, handleSubmit } = useForm({
Expand All @@ -44,60 +45,64 @@ const AddReviewModal: React.FC<AddReviewModalProps> = (
} as ReviewForm,
});

const dispatch = useDispatch<AppDispatch>();
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 ? (
<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>
<div className="relative w-1/4 min-w-[400px] my-6 mx-auto z-40">
Expand All @@ -106,10 +111,10 @@ const AddReviewModal: React.FC<AddReviewModalProps> = (
ref={props.formRef}
>
<div className="flex items-center justify-between p-2 px-4 border-b border-solid border-slate-200 rounded-t">
<h3 className="text-lg font-semibold">Add Review</h3>
<h3 className="text-lg font-semibold">Create New Review</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={() => props.setIsShown(false)}
onClick={() => props.setShow(false)}
>
<span className="bg-transparent text-black text-2xl block outline-none focus:outline-none">
<IoClose size={20} />
Expand All @@ -119,7 +124,7 @@ const AddReviewModal: React.FC<AddReviewModalProps> = (
<div className="relative p-6 flex flex-col items-center gap-6 overflow-auto">
<form
className="w-full gap-2 flex flex-col"
onSubmit={handleSubmit((review) => addReview(review))}
onSubmit={handleSubmit((review) => createNewReview(review))}
>
<Controller
control={control}
Expand Down Expand Up @@ -220,7 +225,9 @@ const AddReviewModal: React.FC<AddReviewModalProps> = (
</div>
</div>
</div>
) : (
<></>
);
};

export default AddReviewModal;
export default CreateReviewModal;
1 change: 0 additions & 1 deletion src/pages/map/MapPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/restaurant/CreateRestaurantPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading