Skip to content

Commit

Permalink
Merge pull request #130 from IT-Cotato/hotfix/COT-6_implement_edit_cs…
Browse files Browse the repository at this point in the history
…_word

Hotfix/cot 6 implement edit cs word
  • Loading branch information
Ea-st-ring authored Oct 6, 2024
2 parents 222a5cd + 90c5ab0 commit ea3f607
Show file tree
Hide file tree
Showing 19 changed files with 336 additions and 134 deletions.
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import FindID from '@pages/Login/FindID';
import FindPWProcess from '@pages/Login/FindPWProcess';
import ReadyState from '@components/ReadyState';
import NotFound from '@components/NotFound';
import CSPage from '@pages/CS/CSPage';

import CotatoThemeProvider from '@theme/context/CotatoThemeProvider';
import GlobalBackgroundSvgComponent from '@components/GlobalBackgroundSvgComponent';
Expand All @@ -22,6 +21,7 @@ import Projects from '@pages/Projects/Projects';
import AttendanceRoutes from '@pages/Attendance/Attendance.routes';
import { AttendanceFab } from '@components/attendance/attendance-fab';
import AgreementConfirmDialog from '@components/AgreementConfirmDialog';
import CSRoutes from '@pages/CS/CSRoutes';

function App() {
const location = useLocation();
Expand Down Expand Up @@ -56,7 +56,7 @@ function App() {
<Route path="/projects" element={<Projects />} />
<Route path="/about" element={<ReadyState />} />
<Route path="/attendance/*" element={<AttendanceRoutes />} />
<Route path="/cs/*" element={<CSPage />} />
<Route path="/cs/*" element={<CSRoutes />} />
<Route path="/session/*" element={<Session />} />
<Route path="/faq" element={<FAQ />} />
<Route path="/findid" element={<FindID />} />
Expand Down
58 changes: 41 additions & 17 deletions src/components/GenerationSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,50 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import { css, styled } from 'styled-components';
import arrow_down_thin from '@assets/arrow_dwon_thin.svg';
import arrow_up_thin from '@assets/arrow_up_thin.svg';
import fetcher from '@utils/fetcher';
import { IGeneration } from '@/typing/db';
import useSWRImmutable from 'swr/immutable';
import generationSort from '@utils/generationSort';
import { CotatoGenerationInfoResponse } from 'cotato-openapi-clients';
import { useParams } from 'react-router-dom';
import { useGeneration } from '@/hooks/useGeneration';

interface Props {
/**
* 기수 변경시 발생해야 하는 로직을 담는 함수
* @param generation
* @returns
*/
onChangeGeneration: (generation?: IGeneration) => void;
onChangeGeneration: (generation?: CotatoGenerationInfoResponse) => void;
/**
* 현재 선택된 기수
*/
selectedGeneration?: IGeneration;
selectedGeneration?: CotatoGenerationInfoResponse;
}

//
//
//

const GenerationSelect = ({ onChangeGeneration, selectedGeneration }: Props) => {
const { data: generationData } = useSWRImmutable<IGeneration[]>('/v1/api/generation', fetcher);
const { generationId } = useParams();
const { generations, targetGeneration } = useGeneration({ generationId });

const [generations, setGenerations] = useState<IGeneration[]>();
const [isOpen, setIsOpen] = useState(false);
const [sortedGenerations, setSortedGenerations] = useState<
CotatoGenerationInfoResponse[] | undefined
>([]);

const generationDropRef = useRef<HTMLDivElement>(null);

/**
*
*/
const onClickGeneration = useCallback((generation: CotatoGenerationInfoResponse) => {
onChangeGeneration(generation);
setIsOpen(false);
}, []);

//
//
//
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (generationDropRef.current && !generationDropRef.current.contains(e.target as Node)) {
Expand All @@ -38,18 +56,24 @@ const GenerationSelect = ({ onChangeGeneration, selectedGeneration }: Props) =>
return () => window.removeEventListener('mousedown', handleClick);
}, [generationDropRef]);

//
//
//
useEffect(() => {
if (generationData) {
const newGenerations = generationSort(generationData);
setGenerations(newGenerations);
onChangeGeneration(newGenerations.at(0));
if (generations) {
const newGenerations = generationSort(generations);
setSortedGenerations(newGenerations);
}
}, [generationData]);
}, [generations]);

const onClickGeneration = useCallback((generation: IGeneration) => {
onChangeGeneration(generation);
setIsOpen(false);
}, []);
//
//
//
useEffect(() => {
if (generationId && targetGeneration) {
onChangeGeneration(targetGeneration);
}
}, [targetGeneration]);

return (
<GenerationSelectWrapper ref={generationDropRef}>
Expand All @@ -65,7 +89,7 @@ const GenerationSelect = ({ onChangeGeneration, selectedGeneration }: Props) =>
{isOpen && (
<GenerationList>
<ul>
{generations?.map((generation: IGeneration) => (
{sortedGenerations?.map((generation) => (
<li key={generation.generationId} onClick={() => onClickGeneration(generation)}>
{`${generation.generationNumber}기`}
</li>
Expand Down
15 changes: 9 additions & 6 deletions src/components/RequestDropBox.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { IGeneration } from '@/typing/db';
import fetcher from '@utils/fetcher';
import { styled } from 'styled-components';
import { ReactComponent as ArrowDown } from '@assets/arrow_dwon_thin.svg';
import { ReactComponent as ArrowUp } from '@assets/arrow_up_thin.svg';
import useSWR from 'swr';
import generationSort from '@utils/generationSort';
import { CotatoGenerationInfoResponse } from 'cotato-openapi-clients';

interface Props {
mode: string;
width: string;
selectedGeneration?: IGeneration;
selectedGeneration?: CotatoGenerationInfoResponse;
selectedPosition?: string;
onChangeGeneration?: (selectedGeneration: IGeneration) => void;
onChangeGeneration?: (selectedGeneration: CotatoGenerationInfoResponse) => void;
onChangePosition?: (selectedPosition: string) => void;
}

Expand All @@ -26,9 +26,12 @@ const RequestDropBox = ({
onChangeGeneration,
onChangePosition,
}: Props) => {
const { data: generationData } = useSWR<IGeneration[]>('/v1/api/generation', fetcher);
const { data: generationData } = useSWR<CotatoGenerationInfoResponse[]>(
'/v1/api/generation',
fetcher,
);

const [generations, setGenerations] = useState<IGeneration[]>();
const [generations, setGenerations] = useState<CotatoGenerationInfoResponse[]>();
const [isOpen, setIsOpen] = useState(false);

const dropRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -66,7 +69,7 @@ const RequestDropBox = ({
}, [mode, selectedGeneration, selectedPosition]);

const onClickGeneration = useCallback(
(generation: IGeneration) => {
(generation: CotatoGenerationInfoResponse) => {
if (onChangeGeneration) onChangeGeneration(generation);
setIsOpen(false);
},
Expand Down
61 changes: 61 additions & 0 deletions src/hooks/useEducation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import fetcherWithParams from '@utils/fetcherWithParams';
import { CotatoAllEducationResponse } from 'cotato-openapi-clients';

import { useRef } from 'react';
import useSWR from 'swr';

//
//
//

interface UseEducationParams {
generationId: number;
educationId?: string;
}

interface UseEducationReturn {
targetEducation: CotatoAllEducationResponse | undefined;
educations: CotatoAllEducationResponse[] | undefined;
isEducationLoading: boolean;
isEducationError: any;
}

//
//
//

export function useEducation({
generationId,
educationId,
}: UseEducationParams): UseEducationReturn {
const _return = useRef<UseEducationReturn>({} as UseEducationReturn);

if (!generationId) {
throw new Error('generationId is required');
}

const { data, isLoading, error } = useSWR<CotatoAllEducationResponse[]>(
'/v1/api/education',
(url) => fetcherWithParams(url, { generationId }),
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateIfStale: false,
},
);

const targetEducation = educationId
? data?.find((education) => education.educationId === Number(educationId))
: undefined;

//
//
//

_return.current.targetEducation = targetEducation;
_return.current.educations = data;
_return.current.isEducationLoading = isLoading;
_return.current.isEducationError = error;

return _return.current;
}
29 changes: 21 additions & 8 deletions src/hooks/useGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ import useSWR from 'swr';
//
//

interface UseGenerationParams {
generationId?: string;
}

interface UseGenerationReturn {
currentGeneration: CotatoGenerationInfoResponse | undefined;
targetGeneration: CotatoGenerationInfoResponse | undefined;
generations: CotatoGenerationInfoResponse[] | undefined;
isGenerationLoading: boolean;
isGenerationError: any;
Expand All @@ -18,7 +23,7 @@ interface UseGenerationReturn {
//
//

export function useGeneration() {
export function useGeneration({ generationId }: UseGenerationParams = {}): UseGenerationReturn {
const _return = useRef<UseGenerationReturn>({} as UseGenerationReturn);

const { data, isLoading, error } = useSWR<CotatoGenerationInfoResponse[]>(
Expand All @@ -31,14 +36,22 @@ export function useGeneration() {
},
);

const currentGeneration = data?.at(-1);
const currentGeneration =
data && data.sort((a, b) => (b.generationId as number) - (a.generationId as number))[0];

const targetGeneration = generationId
? data?.find((generation) => generation.generationId === Number(generationId))
: undefined;

//
//
//

_return.current = {
generations: data,
currentGeneration: currentGeneration,
isGenerationLoading: isLoading,
isGenerationError: error,
};
_return.current.currentGeneration = currentGeneration;
_return.current.targetGeneration = targetGeneration;
_return.current.generations = data;
_return.current.isGenerationLoading = isLoading;
_return.current.isGenerationError = error;

return _return.current;
}
16 changes: 5 additions & 11 deletions src/pages/CS/CSContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { styled, css } from 'styled-components';
import { useNavigate } from 'react-router-dom';
import { ReactComponent as ModifyIcon } from '@assets/modify_icon.svg';
import background from '@assets/cs_content_background.svg';
import { IGeneration, IEducation } from '@/typing/db';
import { IEducation } from '@/typing/db';
import useSWR from 'swr';
import fetcher from '@utils/fetcher';
import { CotatoGenerationInfoResponse } from 'cotato-openapi-clients';

interface Props {
education: IEducation;
handleModifyButton: (education: IEducation) => void;
generation?: IGeneration;
generation?: CotatoGenerationInfoResponse;
}

const CSContent = ({ education, handleModifyButton, generation }: Props) => {
Expand All @@ -20,14 +21,7 @@ const CSContent = ({ education, handleModifyButton, generation }: Props) => {
const navigate = useNavigate();

const onclickContent = useCallback(() => {
navigate(
`/cs/start?generationId=${generation?.generationId}&generationNumber=${generation?.generationNumber}&educationId=${education.educationId}&educationNumber=${education.educationNumber}`,
{
state: {
subject: education.subject,
},
},
);
navigate(`/cs/start/generation/${generation?.generationId}/education/${education.educationId}`);
}, [generation?.generationId, education.educationNumber]);

const onClickModifyButton = useCallback((e: React.MouseEvent<SVGSVGElement>) => {
Expand All @@ -41,7 +35,7 @@ const CSContent = ({ education, handleModifyButton, generation }: Props) => {
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
>
<ContentWeek>{`${education.educationNumber}주차 문제`}</ContentWeek>
<ContentWeek>{`${education.educationNumber}차시 문제`}</ContentWeek>
<ContentTitle>{education.subject}</ContentTitle>
{user?.role === 'ADMIN' && isHover && (
<HoverContent>
Expand Down
37 changes: 37 additions & 0 deletions src/pages/CS/CSGuard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import useUser from '@/hooks/useUser';
import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

//
//
//

const CSGuard = ({ children }: { children: React.ReactNode }) => {
const navigate = useNavigate();

const { user, isUserError, isUserLoading } = useUser();

//
//
//
useEffect(() => {
if (isUserLoading) {
return;
}

if (isUserError || user?.role === 'GENERAL') {
window.alert('코테이토 회원 전용 페이지입니다.');
navigate('/');

return;
}
}, [isUserError, isUserLoading, user]);

//
//
//

return <>{children}</>;
};

export default CSGuard;
Loading

0 comments on commit ea3f607

Please sign in to comment.