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

[Refactor] context provider를 컴포넌트로 분리 #437

Merged
merged 11 commits into from
Aug 28, 2024
45 changes: 11 additions & 34 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { add, init } from '@amplitude/analytics-browser';
import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser';
import { colors } from '@sopt-makers/colors';
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { AxiosError } from 'axios';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { RouterProvider, createBrowserRouter } from 'react-router-dom';

import Layout from '@components/Layout';
import { useDevice } from '@hooks/useDevice';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { RecruitingInfoContext, RecruitingInfoType } from '@store/recruitingInfoContext';
import { ModeType, ThemeContext } from '@store/themeContext';
import DeviceTypeProvider from 'contexts/DeviceTypeProvider';
import RecruitingInfoProvider from 'contexts/RecruitingInfoProvider';
import ThemeProvider, { useTheme } from 'contexts/ThemeProvider';
import { dark, light } from 'styles/theme.css';
import { SessionExpiredDialog } from 'views/dialogs';
import ErrorPage from 'views/ErrorPage';
Expand Down Expand Up @@ -54,10 +52,8 @@ const App = () => {
// }, []);

const sessionRef = useRef<HTMLDialogElement>(null);

const [isLight, setIsLight] = useState(true);
const [recruitingInfo, setRecruitingInfo] = useState<RecruitingInfoType>({});
const [isAmplitudeInitialized, setIsAmplitudeInitialized] = useState(false);
const { isLight } = useTheme();

const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -93,25 +89,6 @@ const App = () => {
}),
});

const themeContextValue = {
isLight,
handleChangeMode: (mode: ModeType) => {
setIsLight(mode === 'light' ? true : false);
const body = document.body;
const bodyColor = mode === 'light' ? colors.white : colors.gray950; // theme.color.background
body.style.backgroundColor = bodyColor;
},
};

const recruitingInfoContextValue = {
recruitingInfo,
handleSaveRecruitingInfo: useCallback((obj: RecruitingInfoType) => {
setRecruitingInfo((prev) => ({ ...prev, ...obj }));
}, []),
};

const deviceType = useDevice();

useEffect(() => {
if (!isAmplitudeInitialized) {
init(import.meta.env.VITE_AMPLITUDE_API_KEY);
Expand All @@ -130,18 +107,18 @@ const App = () => {
return (
<>
<SessionExpiredDialog ref={sessionRef} />
<ThemeContext.Provider value={themeContextValue}>
<DeviceTypeContext.Provider value={{ deviceType }}>
<RecruitingInfoContext.Provider value={recruitingInfoContextValue}>
<ThemeProvider>
<DeviceTypeProvider>
<RecruitingInfoProvider>
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
<div className={isLight ? light : dark}>
<RouterProvider router={router} />
</div>
</QueryClientProvider>
</RecruitingInfoContext.Provider>
</DeviceTypeContext.Provider>
</ThemeContext.Provider>
</RecruitingInfoProvider>
</DeviceTypeProvider>
</ThemeProvider>
</>
);
};
Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useContext, useId, type ButtonHTMLAttributes, type ReactNode } from 'react';
import { useId, type ButtonHTMLAttributes, type ReactNode } from 'react';
import { Link, To } from 'react-router-dom';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';
import ButtonLoading from 'views/loadings/ButtonLoading';

import { buttonFontVar, container, outsideBox, paddings } from './style.css';
Expand All @@ -26,7 +26,7 @@ const Button = ({
isLink = false,
...buttonElementProps
}: ButtonProps) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
const { disabled, type = 'button' } = buttonElementProps;
const Tag = isLink ? Link : 'button';

Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Callout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { colors } from '@sopt-makers/colors';
import { IconAlertCircle } from '@sopt-makers/icons';
import { useContext, type HTMLAttributes, type ReactNode } from 'react';
import { type HTMLAttributes, type ReactNode } from 'react';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { buttonVar, container, warningWrapperVar } from './style.css';

Expand All @@ -13,7 +13,7 @@ interface CalloutProps extends HTMLAttributes<HTMLElement> {
}

const Callout = ({ children, size = 'sm', Button, ...calloutElementProps }: CalloutProps) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
return (
<article className={container[deviceType === 'DESK' ? size : deviceType]} {...calloutElementProps}>
<div className={warningWrapperVar[deviceType]}>
Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { forwardRef, useContext, type DialogHTMLAttributes, type ReactNode } from 'react';
import { forwardRef, type DialogHTMLAttributes, type ReactNode } from 'react';
import { createPortal } from 'react-dom';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { containerVar } from './style.css';

Expand All @@ -10,7 +10,7 @@ interface DialogProps extends DialogHTMLAttributes<HTMLDialogElement> {
}

const Dialog = forwardRef<HTMLDialogElement, DialogProps>(({ children, ...dialogElementProps }: DialogProps, ref) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();

return createPortal(
<dialog ref={ref} className={containerVar[deviceType]} {...dialogElementProps}>
Expand Down
6 changes: 2 additions & 4 deletions src/common/components/Input/components/Description/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { useContext } from 'react';

import { TextBoxProps } from '@components/Input/types';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { descriptionFontVar, descriptionVar } from './style.css';

// TextBox 내부 Input 하단의 부가텍스트
const Description = ({ children, styleType = 'default' }: Pick<TextBoxProps, 'children' | 'styleType'>) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();

return <div className={`${descriptionVar[styleType]} ${descriptionFontVar[deviceType]}`}>{children}</div>;
};
Expand Down
6 changes: 2 additions & 4 deletions src/common/components/Input/components/InputButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { useContext } from 'react';

import Button from '@components/Button';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { buttonVar } from './style.css';
import { InputButtonProps } from './types';

// TextBox 내부 InputLine 우측 버튼
const InputButton = ({ isLoading, text, ...props }: InputButtonProps) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
return (
<Button isLoading={isLoading} className={buttonVar[deviceType]} {...props}>
{text}
Expand Down
4 changes: 2 additions & 2 deletions src/common/components/Input/components/InputLine/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeEvent, useContext } from 'react';
import { useFormContext } from 'react-hook-form';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { inputFont, inputLineVar, inputVar } from './style.css';
import { formatBirthdate } from './utils/formatBirthdate';
Expand All @@ -27,7 +27,7 @@ const InputLine = ({
setValue,
} = useFormContext();
const { required } = useContext(FormContext);
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
const { maxLength, minLength } = inputElementProps;
const { defaultValue } = inputElementProps;

Expand Down
8 changes: 4 additions & 4 deletions src/common/components/Input/components/InputTheme/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { track } from '@amplitude/analytics-browser';
import { useCallback, useContext, useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useLocation, useNavigate } from 'react-router-dom';

Expand All @@ -9,7 +9,7 @@ import useMutateCheckUser from '@components/Input/hooks/useMutateCheckUser';
import useMutateSendCode from '@components/Input/hooks/useMutateSendCode';
import { VALIDATION_CHECK } from '@constants/validationCheck';
import useScrollToHash from '@hooks/useScrollToHash';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { successVar } from './style.css';
import InputLine from '../InputLine';
Expand Down Expand Up @@ -40,7 +40,7 @@ export const TextBox이메일 = ({
isVerified,
onChangeVerification,
}: TextBox이메일Props) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
const location = useLocation();
const navigate = useNavigate();

Expand Down Expand Up @@ -188,7 +188,7 @@ export const TextBox이메일 = ({
};

export const TextBox비밀번호 = () => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();

const location = useLocation();
const textVar = location.pathname === '/password' ? '새 비밀번호' : '비밀번호';
Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Input/components/TextBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createContext, useContext } from 'react';
import { createContext } from 'react';

import { TextBoxProps } from '@components/Input/types';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { circle, containerVar, titleVar } from './style.css';

Expand All @@ -15,7 +15,7 @@ export const TextBox = ({
size = 'md',
required,
}: Pick<TextBoxProps, 'children' | 'label' | 'name' | 'size' | 'required'>) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();

return (
<FormContext.Provider value={{ required }}>
Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Input/components/Timer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { differenceInSeconds } from 'date-fns';
import { useContext, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { timerVar } from './style.css';
import { TimerProps } from './types';
Expand All @@ -11,7 +11,7 @@ const INITIAL_TIME = 300;

// TextBox 내부 타이머
const Timer = ({ isActive, onResetTimer }: TimerProps) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
const [seconds, setSeconds] = useState(INITIAL_TIME - 1);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { track } from '@amplitude/analytics-browser';
import { useContext } from 'react';
import { NavLink } from 'react-router-dom';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import { menuItemVar, menuLinkVar } from './style.css';

Expand All @@ -16,7 +15,7 @@ interface MenuItemProps {
}

const MenuItem = ({ text, path, target, amplitudeId, className, onClick }: MenuItemProps) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();

return (
<li className={`${className} ${menuItemVar[deviceType]}`}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { reset, track } from '@amplitude/analytics-browser';
import { useContext, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { RecruitingInfoContext } from '@store/recruitingInfoContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';
import { useRecruitingInfo } from 'contexts/RecruitingInfoProvider';

import { dimmedBgVar, menuContainerVar, menuList, menuMobListVar } from './style.css';
import { MENU_ITEMS, MENU_ITEMS_MAKERS } from '../../contants';
import MenuItem from '../MenuItem';

const MenuList = ({ isMenuOpen, onClickMenuToggle }: { isMenuOpen?: boolean; onClickMenuToggle?: () => void }) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
const navigate = useNavigate();
const { pathname } = useLocation();
const [isShown, setIsShown] = useState(isMenuOpen);
Expand All @@ -31,7 +31,7 @@ const MenuList = ({ isMenuOpen, onClickMenuToggle }: { isMenuOpen?: boolean; onC

const {
recruitingInfo: { name, isMakers },
} = useContext(RecruitingInfoContext);
} = useRecruitingInfo();
const menuItems = isMakers ? MENU_ITEMS_MAKERS : MENU_ITEMS;
const handleLogout = () => {
track('click-gnb-logout');
Expand Down
9 changes: 4 additions & 5 deletions src/common/components/Layout/components/Header/Nav/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { IconMenu, IconXClose } from '@sopt-makers/icons';
import { useContext } from 'react';

import { DeviceTypeContext } from '@store/deviceTypeContext';
import { ThemeContext } from '@store/themeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';
import { useTheme } from 'contexts/ThemeProvider';
import { theme } from 'styles/theme.css';

import MenuList from './MenuList';
import { menuIconVar } from './style.css';

const Nav = ({ isMenuOpen, onClickMenuToggle }: { isMenuOpen: boolean; onClickMenuToggle: () => void }) => {
const { deviceType } = useContext(DeviceTypeContext);
const { isLight } = useContext(ThemeContext);
const { deviceType } = useDeviceType();
const { isLight } = useTheme();

return deviceType !== 'DESK' ? (
<i className={menuIconVar[deviceType]} onClick={onClickMenuToggle}>
Expand Down
14 changes: 7 additions & 7 deletions src/common/components/Layout/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { useContext, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import MakersDarkLogo from '@assets/MakersDarkLogo';
import MakersLogo from '@assets/MakersLogo';
import NowsoptLogo from '@assets/NowsoptLogo';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { RecruitingInfoContext } from '@store/recruitingInfoContext';
import { ThemeContext } from '@store/themeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';
import { useRecruitingInfo } from 'contexts/RecruitingInfoProvider';
import { useTheme } from 'contexts/ThemeProvider';

import Nav from './Nav';
import MenuList from './Nav/MenuList';
import { containerSizeVer, containerVar, logoVar } from './style.css';

const Header = () => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const handleClickMenuToggle = () => {
setIsMenuOpen((prev) => !prev);
Expand All @@ -24,8 +24,8 @@ const Header = () => {

const {
recruitingInfo: { isMakers },
} = useContext(RecruitingInfoContext);
const { isLight } = useContext(ThemeContext);
} = useRecruitingInfo();
const { isLight } = useTheme();

const handleClickLogo = () => {
pathname === '/' ? window.location.reload() : navigate('/');
Expand Down
6 changes: 3 additions & 3 deletions src/common/components/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { IconChevronDown } from '@sopt-makers/icons';
import { ChangeEvent, useContext } from 'react';
import { ChangeEvent } from 'react';
import { useFormContext } from 'react-hook-form';

import { circle, containerVar, titleVar } from '@components/Input/components/TextBox/style.css';
import { DeviceTypeContext } from '@store/deviceTypeContext';
import { useDeviceType } from 'contexts/DeviceTypeProvider';

import {
errorVar,
Expand All @@ -17,7 +17,7 @@ import {
import { SelectBoxProps } from './type';

const SelectBox = ({ label, name, options, size = 'sm', required, ...inputElementProps }: SelectBoxProps) => {
const { deviceType } = useContext(DeviceTypeContext);
const { deviceType } = useDeviceType();

const { register, formState, clearErrors, getValues, setValue, setError } = useFormContext();
const { errors } = formState;
Expand Down
Loading