Skip to content

Commit

Permalink
Merge pull request #331 from woowacourse-teams/dev/fe
Browse files Browse the repository at this point in the history
[FE] 3차 데모데이 - 1차 QA 후 수정사항 반영
  • Loading branch information
vi-wolhwa authored Aug 7, 2024
2 parents 2daa178 + 826471a commit effb8ab
Show file tree
Hide file tree
Showing 23 changed files with 648 additions and 95 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/frontend_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ jobs:
run: |
echo "REACT_APP_API_URL=${{ secrets.REACT_APP_API_URL }}" > ${{ env.frontend-directory }}/.env.production
echo "REACT_APP_BASE_URL=${{ secrets.REACT_APP_BASE_URL }}" >> ${{ env.frontend-directory }}/.env.production
echo "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" >> ${{ env.frontend-directory }}/.env.production
echo "SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> ${{ env.frontend-directory }}/.env.production
echo "SENTRY_DSN=${{ secrets.SENTRY_AUTH_TOKEN }}" >> ${{ env.frontend-directory }}/.env.sentry-build-plugin
- name: Set environment file permissions
run: chmod 644 ${{ env.frontend-directory }}/.env.production

- name: Set Sentry environment file permissions
run: chmod 644 ${{ env.frontend-directory }}/.env.sentry-build-plugin

- name: Install Dependencies
run: npm install
working-directory: ${{ env.frontend-directory }}
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@

### Environment Variable ###
.env

*.crt
*.csr
*.key
*.pem
1 change: 1 addition & 0 deletions frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { customFetch } from './customFetch';
export { QUERY_KEY } from './queryKeys';
export {
TEMPLATE_API_URL,
PAGE_SIZE,
getTemplateList,
getTemplate,
postTemplate,
Expand Down
1 change: 0 additions & 1 deletion frontend/src/api/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export const QUERY_KEY = {
CATEGORY: 'category',
CATEGORY_LIST: 'categoryList',
CHECK_EMAIL: 'checkEmail',
CHECK_USERNAME: 'userName',
Expand Down
29 changes: 20 additions & 9 deletions frontend/src/api/templates.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
import type { Template, TemplateEditRequest, TemplateListResponse, TemplateUploadRequest } from '@/types';
import type {
Template,
TemplateEditRequest,
TemplateListResponse,
TemplateUploadRequest,
TemplateListRequest,
} from '@/types';
import { customFetch } from './customFetch';

const API_URL = process.env.REACT_APP_API_URL;

export const TEMPLATE_API_URL = `${API_URL}/templates`;

export const getTemplateList = async (
categoryId?: number,
tagId?: number,
page: number = 1,
pageSize: number = 20,
): Promise<TemplateListResponse> => {
export const PAGE_SIZE = 20;

export const getTemplateList = async ({
categoryId,
tagIds,
page = 1,
pageSize = PAGE_SIZE,
keyword = '',
}: TemplateListRequest): Promise<TemplateListResponse> => {
const url = new URL(TEMPLATE_API_URL);

url.searchParams.append('keyword', keyword);

if (categoryId) {
url.searchParams.append('categoryId', categoryId.toString());
}

if (tagId) {
url.searchParams.append('tags', tagId.toString());
if (tagIds) {
url.searchParams.append('tagIds', tagIds.toString());
}

url.searchParams.append('pageNumber', page.toString());
Expand Down
15 changes: 6 additions & 9 deletions frontend/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Link } from 'react-router-dom';

import { logoIcon, newTemplateIcon, userMenuIcon } from '@/assets/images';
import { logoIcon, newTemplateIcon } from '@/assets/images';
import { Button, Flex, Heading, Text } from '@/components';
import { useCheckLoginState } from '@/hooks/authentication';
import { useAuth } from '@/hooks/authentication/useAuth';
import { useLogoutMutation } from '@/queries/authentication/useLogoutMutation';
import { theme } from '../../style/theme';
Expand All @@ -11,8 +10,6 @@ import * as S from './Header.style';
const Header = ({ headerRef }: { headerRef: React.RefObject<HTMLDivElement> }) => {
const { isLogin } = useAuth();

useCheckLoginState();

return (
<S.HeaderContainer ref={headerRef}>
<S.HeaderContentContainer>
Expand All @@ -28,7 +25,7 @@ const Header = ({ headerRef }: { headerRef: React.RefObject<HTMLDivElement> }) =
<img src={newTemplateIcon} alt='' />새 템플릿
</Button>
</Link>
{isLogin ? <UserMenuButton /> : <LoginButton />}
{isLogin ? <LogoutButton /> : <LoginButton />}
</Flex>
</S.HeaderContentContainer>
</S.HeaderContainer>
Expand All @@ -54,17 +51,17 @@ const NavOption = ({ route, name }: { route: string; name: string }) => (
</Link>
);

const UserMenuButton = () => {
const LogoutButton = () => {
const { mutateAsync } = useLogoutMutation();

const handleLogoutButton = async () => {
await mutateAsync();
};

return (
<S.UserMenuButton onClick={handleLogoutButton}>
<img src={userMenuIcon} alt='사용자 메뉴' />
</S.UserMenuButton>
<Button variant='text' size='medium' weight='bold' hoverStyle='none' onClick={handleLogoutButton}>
로그아웃
</Button>
);
};

Expand Down
11 changes: 6 additions & 5 deletions frontend/src/hooks/authentication/useCheckLoginState.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

import { ToastContext } from '@/context/ToastContext';
import { useLoginStateQuery } from '@/queries/authentication/useLoginStateQuery';
import useCustomContext from '../utils/useCustomContext';
import { useAuth } from './useAuth';

export const useCheckLoginState = () => {
const { error, isError, isSuccess } = useLoginStateQuery();
const { error, isError, status } = useLoginStateQuery();
const navigate = useNavigate();
const { handleLoginState } = useAuth();
const { infoAlert } = useCustomContext(ToastContext);

const handleLoginNavigate = useCallback(() => {
navigate('/login');
}, [navigate]);

useEffect(() => {
if (isError) {
alert(error.message);
handleLoginNavigate();
handleLoginState(false);
}

if (isSuccess) {
if (status === 'success') {
handleLoginState(true);
}
}, [error, isError, isSuccess, handleLoginNavigate, handleLoginState]);
}, [error, isError, status, handleLoginNavigate, handleLoginState, infoAlert]);
};
9 changes: 9 additions & 0 deletions frontend/src/hooks/authentication/useLoginForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import { FormEvent } from 'react';
import { useNavigate } from 'react-router-dom';

import { postLogin } from '@/api/authentication';
import { ToastContext } from '@/context/ToastContext';
import { useInputWithValidate } from '../useInputWithValidate';
import useCustomContext from '../utils/useCustomContext';
import { useAuth } from './useAuth';
import { validateEmail, validatePassword } from './validates';

export const useLoginForm = () => {
const navigate = useNavigate();
const { failAlert, successAlert } = useCustomContext(ToastContext);

const { handleLoginState } = useAuth();

const {
value: email,
Expand All @@ -30,11 +36,14 @@ export const useLoginForm = () => {

if (!response.ok) {
console.error(response);
failAlert('로그인에 실패하였습니다.');

return;
}

handleLoginState(true);
navigate('/');
successAlert('로그인 성공!');
}
};

Expand Down
1 change: 1 addition & 0 deletions frontend/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { useWindowWidth } from './useWindowWidth';
export { useDebounce } from './utils/useDebounce';
17 changes: 17 additions & 0 deletions frontend/src/hooks/utils/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useState, useEffect } from 'react';

export const useDebounce = (value: string, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);

return () => {
clearTimeout(handler);
};
}, [value, delay]);

return debouncedValue;
};
4 changes: 4 additions & 0 deletions frontend/src/mocks/categoryList.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"categories": [
{
"id": 1,
"name": "카테고리 없음"
},
{
"id": 2,
"name": "Category1"
Expand Down
18 changes: 14 additions & 4 deletions frontend/src/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,30 @@ import mockTemplateList from './templateList.json';
export const templateHandlers = [
http.get(`${TEMPLATE_API_URL}`, (req) => {
const url = new URL(req.request.url);
const categoryId = url.searchParams.get('category');
const tagId = url.searchParams.get('tag');
const keyword = url.searchParams.get('keyword');
const categoryId = url.searchParams.get('categoryId');
const tagIds = url.searchParams.get('tagIds');
const page = parseInt(url.searchParams.get('page') || '1', 10);
const pageSize = parseInt(url.searchParams.get('pageSize') || '20', 10);

let filteredTemplates = mockTemplateList.templates;

if (keyword) {
filteredTemplates = filteredTemplates.filter(
(template) =>
template.title.includes(keyword) ||
template.description.includes(keyword) ||
template.snippets.some((snippet) => snippet.content.includes(keyword)),
);
}

if (categoryId) {
filteredTemplates = filteredTemplates.filter((template) => template.category.id.toString() === categoryId);
}

if (tagId) {
if (tagIds) {
filteredTemplates = filteredTemplates.filter((template) =>
template.tags.some((tag) => tag.id.toString() === tagId),
template.tags.some((tag) => tagIds.split(',').includes(tag.id.toString())),
);
}

Expand Down
Loading

0 comments on commit effb8ab

Please sign in to comment.