Skip to content

Commit

Permalink
build: 프로젝트 초기 세팅
Browse files Browse the repository at this point in the history
- 변수명 sold out 변경
  • Loading branch information
junghaesung79 committed Jun 12, 2024
1 parent e41e2bf commit 7519041
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 88 deletions.
9 changes: 8 additions & 1 deletion src/api/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { accessClient, client } from 'api';
import { CoopMeResponse, LoginParams, LoginResponse } from 'models/auth';
import {
CoopMeResponse, LoginParams, LoginResponse, RefreshParams, RefreshResponse,
} from 'models/auth';

export const postLogin = async (param: LoginParams) => {
const { data } = await client.post<LoginResponse>('/user/login', param);
Expand All @@ -8,6 +10,11 @@ export const postLogin = async (param: LoginParams) => {

export const postLogout = () => accessClient.post('/user/logout');

export const postRefresh = async (params: RefreshParams) => {
const { data } = await client.post<RefreshResponse>('/user/refresh', params);
return RefreshResponse.parse(data);
};

export const getCoopMe = async () => {
const { data } = await accessClient.get<CoopMeResponse>('/user/coop/me');
return CoopMeResponse.parse(data);
Expand Down
2 changes: 1 addition & 1 deletion src/api/coop/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { accessClient } from 'api';
import { DiningImagesParams, SoldOutParams } from 'models/coop';

export const updateSoldOut = async (data: SoldOutParams) => {
export const patchSoldOut = async (data: SoldOutParams) => {
await accessClient.patch<SoldOutParams>('/coop/dining/soldout', data);
};

Expand Down
File renamed without changes
4 changes: 2 additions & 2 deletions src/models/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export interface LoginForm extends LoginParams {
}

export const LoginResponse = z.object({
refresh_token: z.string(),
token: z.string(),
user_type: z.string(),
refresh_token: z.string(),
user_type: z.string(), // 삭제 가능성 있음
});

export type LoginResponse = z.infer<typeof LoginResponse>;
Expand Down
2 changes: 1 addition & 1 deletion src/models/dinings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const DINING_TYPE_MAP = {
DINNER: '저녁',
} as const;

export type Place = 'A코너' | 'B코너' | 'C코너' | '능수관' | '2캠퍼스';
export type DiningPlace = 'A코너' | 'B코너' | 'C코너' | '능수관' | '2캠퍼스';

export const PlaceSchema = z.union([
z.literal('A코너'),
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Coop/components/MenuCard/MenuCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
object-fit: cover;
}

&--soldout {
&--sold-out {
width: 150px;
height: 100px;
background: linear-gradient(0deg, rgb(0 0 0 / 50%) 0%, rgb(0 0 0 / 50%) 100%);
Expand Down Expand Up @@ -110,7 +110,7 @@
}
}

&__soldout {
&__sold-out {
color: #8e8e8e;
font-size: 13px;
font-weight: 400;
Expand Down
98 changes: 46 additions & 52 deletions src/pages/Coop/components/MenuCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/* eslint-disable no-nested-ternary */
import { useEffect, useRef, useState } from 'react';

import { getCoopUrl } from 'api/uploadFile/index';
import Photo from 'assets/svg/coop/photo.svg?react';
import SoldOut from 'assets/svg/coop/soldout.svg?react';
import { Dinings, Corner } from 'models/coop';
import { DiningType, DINING_TYPE_MAP } from 'models/dinings';
import SoldoutModal from 'pages/Coop/components/SoldoutModal';
import SoldoutToggle from 'pages/Coop/components/SoldoutToggle';
import SoldOut from 'assets/svg/coop/sold-out.svg?react';
import { DiningPlace, Dinings, DiningType } from 'models/dinings';
import SoldOutModal from 'pages/Coop/components/SoldOutModal';
import SoldOutToggle from 'pages/Coop/components/SoldOutToggle';
import { getOpenMenuType, OperatingStatus, OPEN } from 'pages/Coop/hook/useGetCurrentMenuType';
import { useGetDining, useUploadDiningImage, useUpdateSoldOut } from 'query/coop';
import { useUploadDiningImage, useSoldOut } from 'query/coop';
import { useGetDining } from 'query/dinings';

import axios from 'axios';

Expand All @@ -27,11 +26,11 @@ interface FileInfo {

export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardProps) {
const { uploadDiningImageMutation } = useUploadDiningImage();
const { updateSoldOutMutation } = useUpdateSoldOut();
const { updateSoldOut: updateSoldOutMutation } = useSoldOut();
const fileInputRefs = useRef<{ [key: number]: HTMLInputElement | null }>({});
const [isSoldoutModalOpen, setIsSoldoutModalOpen] = useState(false);
const [isSoldOutModalOpen, setIsSoldOutModalOpen] = useState(false);
const [selectedMenu, setSelectedMenu] = useState<Dinings | null>(null);
const [selectedCorner, setSelectedCorner] = useState<Corner | null>(null);
const [selectedPlace, setSelectedPlace] = useState<DiningPlace | null>(null);
const [formmatDate, setFormmatDate] = useState<string>('');
const { data } = useGetDining(formmatDate);
const [openMenu, setOpenMenu] = useState<OperatingStatus>(
Expand Down Expand Up @@ -70,45 +69,40 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
fileInputRefs.current[menuId]?.click();
};

const getDiningType = (menuType: DiningType) => DINING_TYPE_MAP[menuType];
const filteredData = data?.filter((menu: Dinings) => ['A코너', 'B코너', 'C코너'].includes(menu.place));

const filteredData = data?.filter((menu:Dinings) => {
const diningType = getDiningType(selectedMenuType);
return menu.type === diningType && ['A코너', 'B코너', 'C코너'].includes(menu.place);
});

const getDiningDataForCorner = (corner: Corner, diningData: Dinings[]):
const getDiningDataForCorner = (place: DiningPlace, diningData: Dinings[]):
Dinings | null => diningData.find(
(menu) => menu.place === corner,
(menu) => menu.place === place,
) || null;

const handleToggleSoldoutModal = (menu?: Dinings, corner?: Corner) => {
const handleToggleSoldOutModal = (menu: Dinings, type: DiningType) => {
setSelectedMenu(menu || null);
setSelectedCorner(corner || null);
setSelectedPlace(type || null);
if (menu?.soldout_at === null) {
setIsSoldoutModalOpen((prev) => !prev);
setIsSoldOutModalOpen((prev) => !prev);
} else if (menu) {
setIsSoldoutModalOpen((prev) => !prev);
setIsSoldOutModalOpen((prev) => !prev);
}
};

const handleSoldoutModalClose = () => {
setIsSoldoutModalOpen(false);
const handleSoldOutModalClose = () => {
setIsSoldOutModalOpen(false);
};

const handleSoldoutModalConfirm = () => {
const handleSoldOutModalConfirm = () => {
if (selectedMenu && selectedMenu.soldout_at === null) {
updateSoldOutMutation({
menu_id: selectedMenu.id,
sold_out: true,
});
setIsSoldoutModalOpen(false);
setIsSoldOutModalOpen(false);
} else if (selectedMenu && selectedMenu.soldout_at) {
updateSoldOutMutation({
menu_id: selectedMenu.id,
sold_out: false,
});
setIsSoldoutModalOpen(false);
setIsSoldOutModalOpen(false);
}
};

Expand All @@ -129,14 +123,14 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
return (
<>
<div className={styles.container}>
{(['A코너', 'B코너', 'C코너'] as Corner[]).map((corner) => {
const menu = getDiningDataForCorner(corner, filteredData);
{(['A코너', 'B코너', 'C코너'] as const).map((place) => {
const menu = getDiningDataForCorner(place, filteredData);
return (
<div key={corner} className={styles.card}>
<div key={place} className={styles.card}>
<div className={styles.card__header}>
{menu && menu.changed_at !== null ? (
<div className={styles['card__common-wrapper']}>
<span className={styles.card__title}>{corner}</span>
<span className={styles.card__title}>{place}</span>
<div className={styles.card__kcal}>
{menu.kcal}
kcal
Expand All @@ -147,7 +141,7 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro

menu && (
<div className={styles['card__common-wrapper']}>
<span className={styles.card__title}>{corner}</span>
<span className={styles.card__title}>{place}</span>
<div className={styles.card__kcal}>
{menu.kcal}
kcal
Expand All @@ -159,8 +153,8 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
<div className={styles['card__common-wrapper']}>
{menu && <span className={styles.card__soldout}>품절</span>}
{menu && (
<SoldoutToggle
onClick={() => handleToggleSoldoutModal(menu, corner)}
<SoldOutToggle
onClick={() => handleToggleSoldOutModal(menu)}
menu={menu}
/>
)}
Expand Down Expand Up @@ -189,7 +183,7 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
))}

{menu.soldout_at && (
<div className={styles['card__image--soldout']}>
<div className={styles['card__image--sold-out']}>
<SoldOut />
<span>품절된 메뉴입니다.</span>
</div>
Expand All @@ -204,7 +198,7 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
</>
) : (
<div className={styles['card__content--none']}>
{corner}
{place}
에서 제공하는 식단 정보가 없습니다.
</div>
)}
Expand All @@ -224,49 +218,49 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
);
})}
</div>
<SoldoutModal
<SoldOutModal
modalSize="mobile"
hasFooter={false}
isOpen={isSoldoutModalOpen}
isOpen={isSoldOutModalOpen}
isOverflowVisible
onCancel={handleSoldoutModalClose}
onCancel={handleSoldOutModalClose}
buttonText="품절설정"
>
{openMenu === OPEN ? (
selectedMenu?.soldout_at === null ? (
<div className={styles.modal}>
<span className={styles.modal__header}>
{selectedCorner}
{selectedPlace}
{' '}
<span className={styles['modal__header--primary']}>품절 상태</span>
로 설정할까요?
</span>
<span className={styles.modal__description}>알림이 발송되니 신중하게 설정해주세요.</span>
<div className={styles.modal__wrapper}>
<button type="button" onClick={handleSoldoutModalClose} className={styles.modal__button}>
<button type="button" onClick={handleSoldOutModalClose} className={styles.modal__button}>
취소
</button>
<button type="button" onClick={handleSoldoutModalConfirm} className={styles['modal__button--primary']}>
<button type="button" onClick={handleSoldOutModalConfirm} className={styles['modal__button--primary']}>
품절설정
</button>
</div>
</div>
) : (
<div className={styles.modal}>
<span className={styles.modal__header}>
{selectedCorner}
{selectedPlace}
{' '}
<span className={styles['modal__header--primary']}>품절 취소</span>
로 설정할까요?
</span>
<span className={styles.modal__description}>이미 발송된 알림은 취소되지 않습니다.</span>
<div className={styles.modal__wrapper}>
<button type="button" onClick={handleSoldoutModalClose} className={styles.modal__button}>
<button type="button" onClick={handleSoldOutModalClose} className={styles.modal__button}>
취소
</button>
<button type="button" onClick={handleSoldoutModalConfirm} className={styles['modal__button--primary']}>
<button type="button" onClick={handleSoldOutModalConfirm} className={styles['modal__button--primary']}>
품절취소
</button>
</div>
Expand All @@ -281,14 +275,14 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
인 식단이 아닙니다.
</span>
<span className={styles.modal__description}>
{selectedCorner}
{selectedPlace}
를 품절 상태로 설정할까요?
</span>
<div className={styles.modal__wrapper}>
<button type="button" onClick={handleSoldoutModalClose} className={styles.modal__button}>
<button type="button" onClick={handleSoldOutModalClose} className={styles.modal__button}>
취소
</button>
<button type="button" onClick={handleSoldoutModalConfirm} className={styles['modal__button--secondary']}>
<button type="button" onClick={handleSoldOutModalConfirm} className={styles['modal__button--secondary']}>
품절설정
</button>
</div>
Expand All @@ -302,20 +296,20 @@ export default function MenuCard({ selectedMenuType, selectedDate }: MenuCardPro
인 식단이 아닙니다.
</span>
<span className={styles.modal__description}>
{selectedCorner}
{selectedPlace}
를 품절 취소로 설정할까요?
</span>
<div className={styles.modal__wrapper}>
<button type="button" onClick={handleSoldoutModalClose} className={styles.modal__button}>
<button type="button" onClick={handleSoldOutModalClose} className={styles.modal__button}>
취소
</button>
<button type="button" onClick={handleSoldoutModalConfirm} className={styles['modal__button--secondary']}>
<button type="button" onClick={handleSoldOutModalConfirm} className={styles['modal__button--secondary']}>
품절취소
</button>
</div>
</div>
))}
</SoldoutModal>
</SoldOutModal>
</>
);
}
4 changes: 2 additions & 2 deletions src/pages/Coop/components/SoldoutToggle/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Dinings } from 'models/coop';
import { Dinings } from 'models/dinings';
import useToggleStore from 'store/useToggleStore';

import styles from './SoldoutToggle.module.scss';
import styles from './SoldOutToggle.module.scss';

interface SoldoutToggleProps {
onClick: () => void;
Expand Down
32 changes: 9 additions & 23 deletions src/query/auth.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,28 @@
import { useNavigate } from 'react-router-dom';

import { postLogin, postLogout } from 'api/auth';
import { LoginForm } from 'models/auth';
import { postLogin, postRefresh, postLogout } from 'api/auth';

Check warning on line 3 in src/query/auth.ts

View workflow job for this annotation

GitHub Actions / ESLint

'postRefresh' is defined but never used

Check warning on line 3 in src/query/auth.ts

View workflow job for this annotation

GitHub Actions / ESLint

'postRefresh' is defined but never used
import { LoginForm, RefreshParams } from 'models/auth';

Check warning on line 4 in src/query/auth.ts

View workflow job for this annotation

GitHub Actions / ESLint

'RefreshParams' is defined but never used

Check warning on line 4 in src/query/auth.ts

View workflow job for this annotation

GitHub Actions / ESLint

'RefreshParams' is defined but never used
import { useErrorMessageStore } from 'store/useErrorMessageStore';

import { isKoinError, sendClientError } from '@bcsdlab/koin';
import { useMutation } from '@tanstack/react-query';

export interface ErrorResponse {
response: undefined | {
message: string;
data: {
code: number;
message: string;
violations: {
field: string;
message: string;
}[];
}
}
message: string;
}

export const useLogin = () => {
const { setLoginError, setLoginErrorStatus } = useErrorMessageStore();
const navigate = useNavigate();

const {
mutate, error, isError, isSuccess,
} = useMutation({
mutationFn: (variables: LoginForm) => postLogin({
email: variables.email, password: variables.password,
mutationFn: (form: LoginForm) => postLogin({
email: form.email, password: form.password,
}),
onSuccess: async (data, variables) => {
if (data.token) { sessionStorage.setItem('access_token', data.token); }
onSuccess: async (data, form) => {
if (data.token) {
sessionStorage.setItem('access_token', data.token);
}

if (variables.isAutoLogin) {
if (form.isAutoLogin) {
localStorage.setItem('refresh_token', data.refresh_token);
}
navigate('/');
Expand Down Expand Up @@ -85,7 +72,6 @@ export const useLogout = () => {
},
onSuccess: () => {
sessionStorage.removeItem('access_token');
sessionStorage.removeItem('user_type');
localStorage.removeItem('refresh_token');
},
onError: (err) => {
Expand Down
Loading

0 comments on commit 7519041

Please sign in to comment.