Skip to content

Commit

Permalink
Merge branch 'develop' into feature/#196
Browse files Browse the repository at this point in the history
  • Loading branch information
hyejun0228 committed Apr 7, 2024
2 parents 877297f + 3e6f599 commit f9c3f7a
Show file tree
Hide file tree
Showing 46 changed files with 1,000 additions and 399 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/CHECK_PR_MERGED.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
on:
pull_request:
types: closed

jobs:
check_pr_merged:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Check PR Merged
id: check_pr_merged
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prUrl = context.payload.pull_request.html_url ?? context.payload.pull_request._links.html.href;
core.setOutput('pullRequestLink', JSON.stringify(prUrl));
- name: Send Slack Trigger
run: |
curl -X POST https://api-slack.internal.bcsdlab.com/api/pr-merged/frontend \
-H 'Content-Type: application/json' \
-d '{
"pullRequestLink": ${{ steps.check_pr_merged.outputs.pullRequestLink }}
}'
38 changes: 20 additions & 18 deletions .github/workflows/PICK_REVIEWER.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,32 @@ jobs:
const prUrl = context.payload.pull_request.html_url;
const prCreatorJson = developers.reviewers.find(person => person.githubName === prCreator);
if (developers.length <= 1) {
core.setOutput('reviewers', developers.reviewers[0]);
core.setOutput('writer', prCreatorJson.name);
core.setOutput('pullRequestLink', prUrl);
//PrCreator가 reviewer에 등록되지 않은 사람인 경우
if (!prCreatorJson) {
const reviewerArr = developers.reviewers;
const randomReviewer1 = getRandomReviewer(reviewerArr);
const randomReviewer2 = getRandomReviewer(reviewerArr.filter(reviewer => reviewer.name !== randomReviewer1.name));
setOutput(prCreator, prUrl, randomReviewer1, randomReviewer2);
} else {
const candidateInternalReviewers = developers.reviewers.filter(person => person.team === prCreatorJson.team && person.githubName !== prCreator);
const candidateExternalReviewers = developers.reviewers.filter(person => person.team !== prCreatorJson.team);
const randomReviewer1 = getRandomReviewer(candidateInternalReviewers);
const randomReviewer2 = getRandomReviewer(candidateExternalReviewers);
setOutput(prCreatorJson.name, prUrl, randomReviewer1, randomReviewer2);
}
const randomReviewer1 = candidateInternalReviewers[Math.floor(Math.random() * candidateInternalReviewers.length)];
const randomReviewer2 = candidateExternalReviewers[Math.floor(Math.random() * candidateExternalReviewers.length)];
core.setOutput('reviewer1Name', JSON.stringify(randomReviewer1.name));
core.setOutput('reviewer2Name', JSON.stringify(randomReviewer2.name));
core.setOutput('reviewer1GithubName', randomReviewer1.githubName);
core.setOutput('reviewer2GithubName', randomReviewer2.githubName);
core.setOutput('writer', JSON.stringify(prCreatorJson.name));
core.setOutput('pullRequestLink', JSON.stringify(prUrl));
function getRandomReviewer(reviewers) {
return reviewers[Math.floor(Math.random() * reviewers.length)];
}
- name: test valiable
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: console.log(${{ steps.pick_random_reviewer.outputs.reviewer1Name }})
function setOutput(prCreator, prUrl, reviewer1, reviewer2) {
core.setOutput('writer', JSON.stringify(prCreator));
core.setOutput('pullRequestLink', JSON.stringify(prUrl));
core.setOutput('reviewer1Name', JSON.stringify(reviewer1.name));
core.setOutput('reviewer2Name', JSON.stringify(reviewer2.name));
core.setOutput('reviewer1GithubName', reviewer1.githubName);
core.setOutput('reviewer2GithubName', reviewer2.githubName);
}
- name: Add Reviewers
uses: madrapps/add-reviewers@v1
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
name="description"
content="backoffice for koin's store owner"
/>
<meta name="google" content="notranslate">
<link rel="icon" type="image/png" sizes="32x32" href="https://static.koreatech.in/assets/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://static.koreatech.in/assets/favicons/favicon-16x16.png">
<link rel="apple-touch-icon" href="https://static.koreatech.in/assets/favicons/favicon-32x32.png" />
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import PageNotFound from 'page/Error/PageNotFound';
import ModifyMenu from 'page/ModifyMenu';
import { Suspense } from 'react';
import Toast from 'component/common/Toast';
import Coop from 'page/Coop';

function App() {
return (
Expand All @@ -28,6 +29,7 @@ function App() {
<Route path="/order-management" element={<PageNotFound />} />
<Route path="/sales-management" element={<PageNotFound />} />
<Route path="/shop-add" element={<PageNotFound />} />
<Route path="/coop" element={<Coop />} />
</Route>
<Route element={<AuthLayout />}>
<Route path="/login" element={<Login />} />
Expand Down
15 changes: 15 additions & 0 deletions src/api/coop/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { accessClient } from 'api';
import { DiningImages, SoldOut } from 'model/Coop';

export const getDining = async () => {
const { data } = await accessClient.get('/dinings');
return data;
};

export const uploadDiningImage = async (data: DiningImages) => {
await accessClient.patch<DiningImages>('/coop/dining/image', data);
};

export const updateSoldOut = async (data: SoldOut) => {
await accessClient.patch<SoldOut>('/coop/dining/soldout', data);
};
46 changes: 40 additions & 6 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* eslint-disable @typescript-eslint/no-throw-literal */
/* eslint-disable no-param-reassign */
/* eslint-disable no-underscore-dangle */
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import API_PATH from 'config/constants';
import { RefreshParams, RefreshResponse } from 'model/auth';
import { CustomAxiosError, KoinError } from 'model/error';

const client = axios.create({
baseURL: `${API_PATH}`,
Expand Down Expand Up @@ -51,20 +53,46 @@ accessClient.interceptors.request.use(
},
);

function isAxiosErrorWithResponseData(error: AxiosError<KoinError>) {
const { response } = error;
return response?.status !== undefined
&& response.data.code !== undefined
&& response.data.message !== undefined;
}

function createKoinErrorFromAxiosError(error: AxiosError<KoinError>): KoinError | CustomAxiosError {
if (isAxiosErrorWithResponseData(error)) {
const koinError = error.response!;
return {
type: 'KOIN_ERROR',
status: koinError.status,
code: koinError.data.code,
message: koinError.data.message,
};
}
return {
type: 'AXIOS_ERROR',
...error,
};
}

client.interceptors.response.use(
(response) => response,
async (error) => { throw createKoinErrorFromAxiosError(error); },
);

accessClient.interceptors.response.use(
(response) => response,
async (error) => {
if (error.message) return Promise.reject(error.message);

const originalRequest = error.config;

// accessToken만료시 새로운 accessToken으로 재요청
// accessToken 만료시 새로운 accessToken으로 재요청
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;

return refresh(originalRequest);
}
return Promise.reject(error);

throw createKoinErrorFromAxiosError(error);
},
);

Expand All @@ -74,4 +102,10 @@ multipartClient.interceptors.request.use(
return config;
},
);

multipartClient.interceptors.response.use(
(response) => response,
async (error) => { throw createKoinErrorFromAxiosError(error); },
);

export { client, accessClient, multipartClient };
8 changes: 8 additions & 0 deletions src/assets/svg/coop/photo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 3 additions & 6 deletions src/component/common/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import useMediaQuery from 'utils/hooks/useMediaQuery';
import { createPortal } from 'react-dom';
import { postLogout } from 'api/auth';
import useUserStore from 'store/user';
import useStepStore from 'store/useStepStore';
import styles from './Header.module.scss';
import useMobileSidebar from './hooks/useMobileSidebar';
import useMegaMenu from './hooks/useMegaMenu';
Expand Down Expand Up @@ -37,15 +36,13 @@ function Header() {
} = useMobileSidebar(pathname, isMobile);
const isMain = true;
const { user, removeUser } = useUserStore();
const setStep = useStepStore((state) => state.setStep);

const logout = () => {
postLogout()
.then(() => {
sessionStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
removeUser();
setStep(0);
});
};

Expand Down Expand Up @@ -89,7 +86,7 @@ function Header() {
</button>
)}
<span className={styles.mobileheader__title}>
{pathname === '/' ? (
{pathname === '/' || pathname === '/coop' ? (
<MobileLogoIcon title="코인 로고" />
) : (CATEGORY
.flatMap((categoryValue) => categoryValue.submenu)
Expand Down Expand Up @@ -155,7 +152,7 @@ function Header() {
key={subMenu.title}
>
<Link to={subMenu.link}>
{subMenu.title}
{subMenu.title === '가게정보' && subMenu.title}
</Link>
</li>
))}
Expand Down Expand Up @@ -238,7 +235,7 @@ function Header() {
{panelMenuList?.map((menu) => (
<li className={styles.megamenu__menu} key={menu.title}>
<Link className={styles.megamenu__link} to={menu.link}>
{menu.title}
{menu.title === '가게정보' && menu.title}
</Link>
</li>
))}
Expand Down
41 changes: 41 additions & 0 deletions src/model/Coop/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import z from 'zod';

export type Menus = '아침' | '점심' | '저녁';

export type DiningTypes = 'BREAKFAST' | 'LUNCH' | 'DINNER';

export const DINING_TYPES: Record<Menus, DiningTypes> = {
아침: 'BREAKFAST',
점심: 'LUNCH',
저녁: 'DINNER',
};

export const Dinings = z.object({
date: z.string(),
id: z.number(),
kcal: z.number(),
menu: z.array(z.string()),
place: z.string(),
price_card: z.number(),
price_cash: z.number(),
type: z.string(),
updated_at: z.string(),
sold_out: z.boolean(),
is_changed: z.boolean(),
});

export type Dinings = z.infer<typeof Dinings>;

export const DiningImages = z.object({
menuId: z.number(),
imageUrl: z.string(),
});

export type DiningImages = z.infer<typeof DiningImages>;

export const SoldOut = z.object({
menuId: z.number(),
soldOut: z.boolean(),
});

export type SoldOut = z.infer<typeof SoldOut>;
12 changes: 12 additions & 0 deletions src/model/error/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { AxiosError } from 'axios';

export interface KoinError {
type: 'KOIN_ERROR';
status: number;
code: number;
message: string;
}

export interface CustomAxiosError extends AxiosError {
type: 'AXIOS_ERROR';
}
15 changes: 8 additions & 7 deletions src/page/AddMenu/components/AddMenuImgModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ import React, { useEffect } from 'react';
import { createPortal } from 'react-dom';
import { ReactComponent as CancelIcon } from 'assets/svg/addmenu/mobile-cancle-icon.svg';
import useAddMenuStore from 'store/addMenu';
import useImageUpload from 'utils/hooks/useImageUpload';
import ErrorMessage from 'page/Auth/Signup/component/ErrorMessage';
import { ERRORMESSAGE } from 'page/ShopRegistration/constant/errorMessage'; import styles from './AddMenuImgModal.module.scss';
import { ERRORMESSAGE } from 'page/ShopRegistration/constant/errorMessage'; import useImagesUpload from 'utils/hooks/useImagesUpload';
import styles from './AddMenuImgModal.module.scss';

interface AddMenuImgModalProps {
isOpen: boolean;
closeModal: (event?: React.MouseEvent | React.KeyboardEvent) => void;
}

export default function AddMenuImgModal({ isOpen, closeModal }: AddMenuImgModalProps) {
const { setImageUrl } = useAddMenuStore();
const { setImageUrls } = useAddMenuStore();

const {
imageFile, imgRef, saveImgFile, uploadError,
} = useImageUpload();
} = useImagesUpload();

const triggerFileInput = () => {
imgRef.current?.click();
Expand All @@ -28,10 +29,10 @@ export default function AddMenuImgModal({ isOpen, closeModal }: AddMenuImgModalP
};
useEffect(() => {
if (imageFile && !uploadError) {
setImageUrl(imageFile);
setImageUrls(imageFile);
closeModal();
}
}, [imageFile, uploadError, setImageUrl, closeModal]);
}, [imageFile, uploadError, setImageUrls, closeModal]);

if (!isOpen) return null;

Expand All @@ -44,7 +45,7 @@ export default function AddMenuImgModal({ isOpen, closeModal }: AddMenuImgModalP
<span className={styles['content__main-text']}>이미지 추가</span>
<span className={styles['content__sub-text']}>메뉴 사진을 추가할 수 있습니다.</span>
<div className={styles['content__button-container']}>
<input type="file" accept="image/*" style={{ display: 'none' }} onChange={handleImageChange} ref={imgRef} />
<input type="file" accept="image/*" style={{ display: 'none' }} onChange={handleImageChange} ref={imgRef} multiple />
<button type="button" className={styles['content__album-button']} onClick={triggerFileInput}>사진 앨범</button>
<button type="button" className={styles['content__camera-button']} onClick={triggerCameraInput}>카메라 촬영</button>
</div>
Expand Down
Loading

0 comments on commit f9c3f7a

Please sign in to comment.