Skip to content

Commit

Permalink
Merge pull request #5 from Read-bird/feature/feat-calendar/youjeong
Browse files Browse the repository at this point in the history
홈 캘린더 화면 UI 구현
  • Loading branch information
devwoodie authored Dec 16, 2023
2 parents d7fe1c2 + d779910 commit f976463
Show file tree
Hide file tree
Showing 42 changed files with 748 additions and 256 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ jobs:
- name: .env setting
run: |
echo "REACT_APP_KAKAO_API_KEY=${{ secrets.REACT_APP_KAKAO_API_KEY }}" >> .env
echo "REACT_APP_SERVER_PATH=${{ secrets.REACT_APP_SERVER_PATH }}" >> .env
env:
REACT_APP_KAKAO_API_KEY: ${{ secrets.REACT_APP_KAKAO_API_KEY }}
REACT_APP_SERVER_PATH: ${{ secrets.REACT_APP_SERVER_PATH }}
- name: Deploy
uses: cloudtype-github-actions/deploy@v1
with:
Expand Down
13 changes: 13 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { setCurrentDate } from '@/store/reducers';
import { TAppDispatch } from '@/store/state';
import { LoadingTemplate } from '@components/templates/LoadingTemplate';
import { appRouter } from '@routers/appRouter';
import { GlobalStyle, theme } from '@style/global-style';
import dayjs from 'dayjs';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { RouterProvider } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';

export const App = () => {
// 첫 접속시 날짜 등록
const dispatch = useDispatch<TAppDispatch>();

useEffect(() => {
// 첫 접속시 당일 날짜 등록
dispatch(setCurrentDate(dayjs().format()));
}, []);

return (
<ThemeProvider theme={theme}>
<GlobalStyle />
Expand Down
7 changes: 7 additions & 0 deletions src/api/types/planRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ export type TPlan = {

// 플랜달성실패 데이터
export type TPreviouslyFailedPlan = Omit<TPlan, 'target' | 'planStatus' | 'recordStatus'>;

// 전체 타입
export type TPlanData = {
weedRecord: TPlanRecord[] | null;
planData: TPlan[] | null;
previouslyFailedPlan: TPreviouslyFailedPlan[] | null;
};
21 changes: 21 additions & 0 deletions src/assets/icons/IconBook.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SVGProps } from 'react';

type TIconProps = {
fillColor?: string;
strokeColor?: string;
} & SVGProps<SVGSVGElement>;

export const IconBook = ({ fillColor = '#E3CCF2', strokeColor = 'white' }: TIconProps) => {
return (
<svg width="46" height="39" viewBox="0 0 46 39" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M34.5 0C28.1534 0 23 4.5918 23 10.2542C23 4.5918 17.8466 0.0128986 11.5 0.0128986C5.15336 0.0128986 0 4.6047 0 10.2671C0 10.2671 0 10.28 0 10.2929V38.2564C0 38.7852 0.563846 38.9916 0.852329 38.5789C2.57012 36.025 6.68757 34.2321 11.5 34.2321C16.3124 34.2321 20.443 36.025 22.1477 38.5789C22.423 38.9916 23 38.7852 23 38.2564C23 38.7852 23.5638 38.9916 23.8523 38.5789C25.5701 36.025 29.6876 34.2321 34.5 34.2321C39.3124 34.2321 43.443 36.025 45.1477 38.5789C45.423 38.9916 46 38.7852 46 38.2564V10.2929C46 10.2929 46 10.28 46 10.2671C46 4.6047 40.8466 0.0128986 34.5 0.0128986V0ZM23 10.28C23 10.28 23 10.28 23 10.2671C23 10.2671 23 10.2671 23 10.28Z"
fill={fillColor}
/>
<path
d="M34.833 12.9697L33.5741 11.7483C32.972 11.1645 32.005 11.1735 31.412 11.7663L21.1491 22.0225L16.1681 17.1908C15.6846 16.7238 14.891 16.7238 14.4166 17.1998L12.7654 18.8523C12.291 19.3282 12.291 20.1096 12.7745 20.5766L20.3189 27.8961C20.8024 28.3631 21.5961 28.3631 22.0705 27.8871L34.8513 15.1072C35.4442 14.5144 35.4351 13.5625 34.833 12.9787V12.9697Z"
fill={strokeColor}
/>
</svg>
);
};
10 changes: 2 additions & 8 deletions src/assets/icons/IconCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,9 @@ type TIconProps = {
strokeColor?: string;
} & SVGProps<SVGSVGElement>;

export const IconCalendar = ({ width = 45, height = 36, fillColor = '#ffffff' }: TIconProps) => {
export const IconCalendar = ({ fillColor = '#ffffff' }: TIconProps) => {
return (
<svg
width={`${width}`}
height={`${height}`}
viewBox={`0 0 ${width} ${height}`}
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg width="45" height="36" viewBox="0 0 45 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M44.4784 26.8512H40.3362C40.7592 25.551 40.9942 24.1619 40.9942 22.725C40.9942 16.6964 36.993 11.5849 31.5686 9.98365V6.48698H38C39.6448 6.48698 40.9942 5.11158 40.9942 3.43509V3.05189C40.9942 1.3754 39.6448 0 38 0H5.92337C4.27859 0 2.92919 1.3754 2.92919 3.05189V3.43509C2.92919 5.11158 4.27859 6.48698 5.92337 6.48698H12.2273V10.0179C9.47476 10.8595 7.10493 12.6181 5.44 14.931L0.720485 14.8557C0.169987 14.8489 -0.17911 15.4511 0.0961393 15.9369L3.03661 21.1306C2.97619 21.6575 2.92919 22.1844 2.92919 22.725C2.92919 30.0262 8.78999 36 15.9532 36H27.9702C32.0653 36 35.7241 34.043 38.1141 31.0116C38.1141 31.0116 38.1208 31.0116 38.1275 31.0116C39.5508 29.6704 42.31 28.6029 44.6328 27.8844C45.2035 27.7065 45.0759 26.8512 44.4784 26.8512ZM15.2147 6.48698H28.5677V9.48413C28.3663 9.47729 28.1716 9.44991 27.9635 9.44991H15.9465C15.6981 9.44991 15.4564 9.47729 15.2147 9.49097V6.48698Z"
fill={fillColor}
Expand Down
31 changes: 31 additions & 0 deletions src/assets/icons/IconDayBirdMini.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { SVGProps } from 'react';

type TIconProps = {
fillColor?: string;
strokeColor?: string;
} & SVGProps<SVGSVGElement>;

export const IconDayBirdMini = ({
fillColor = 'transparent',
strokeColor = '#ABABAB',
...props
}: TIconProps) => {
return (
<svg
width="17"
height="15"
viewBox="0 0 17 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M15.8222 10.3837H14.2193C14.7487 9.30874 14.9944 8.0704 14.8482 6.7604C14.5177 3.75915 12.1017 1.3484 9.10947 1.03595C6.59695 0.775094 4.3389 1.9561 3.05486 3.85661L1.30282 3.73335C1.07175 3.73048 0.925505 3.97987 1.03958 4.18052L2.16568 5.80298C1.92876 6.68587 1.86733 7.64329 2.03991 8.6351C2.51374 11.3726 4.72792 13.5426 7.46859 13.9324C9.62426 14.2392 11.6161 13.4795 12.9909 12.1007C12.9909 12.1007 12.9938 12.1007 12.9967 12.1007C13.6548 11.4902 14.8511 11.0172 15.8748 10.7219C16.0679 10.6675 16.0269 10.378 15.8251 10.378L15.8222 10.3837Z"
fill={fillColor}
stroke={strokeColor}
strokeWidth="0.5"
strokeMiterlimit="10"
/>
</svg>
);
};
6 changes: 4 additions & 2 deletions src/assets/icons/IconReact.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { IconBaseProps } from '@react-icons/all-files';
import { FaPlus } from '@react-icons/all-files/fa/FaPlus';
import { HiDotsHorizontal } from '@react-icons/all-files/hi/HiDotsHorizontal';
import { IoIosArrowBack } from '@react-icons/all-files/io/IoIosArrowBack';
import { IoIosArrowForward } from '@react-icons/all-files/io/IoIosArrowForward';

const Icons = {
dots: HiDotsHorizontal,
plus: FaPlus
arrow_left: IoIosArrowBack,
arrow_right: IoIosArrowForward
};

type TProps = {
Expand Down
2 changes: 2 additions & 0 deletions src/assets/icons/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from './IconBook';
export * from './IconCalendar';
export * from './IconDayBird';
export * from './IconDayBirdMini';
export * from './IconFailed';
export * from './IconHome';
export * from './IconMyPage';
Expand Down
70 changes: 53 additions & 17 deletions src/components/common/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,61 @@
import { useState } from 'react';
import ReactCalendar from 'react-calendar';
import 'react-calendar/dist/Calendar.css';
import { TPlanRecord } from '@api/types';
import { DayBird } from '@components/common/DayBird';
import { cls, getClassByStatus } from '@utils/classname';
import { convertMap } from '@utils/function';
import dayjs from 'dayjs';
import { useCallback, useMemo } from 'react';
import ReactCalendar, { TileContentFunc, TileDisabledFunc } from 'react-calendar';
import '../../../styles/calendar.css';

type ValuePiece = Date | null;
type TProps = {
currentDate: Date;
record: TPlanRecord[];
changeCurrentDate: (date: string) => void;
};

export const Calendar = ({ record, currentDate, changeCurrentDate }: TProps) => {
const planDateRecord = useMemo(() => convertMap(record, 'createdAt'), [record]);
const onChange = (value: Date) => {
changeCurrentDate(dayjs(value).format());
};

type Value = ValuePiece | [ValuePiece, ValuePiece];
const tileContent: TileContentFunc = useCallback(
({ date }) => {
const formatDate = dayjs(date).format('YYYY-MM-DD');

export const Calendar = () => {
const [value, setValue] = useState<Value>(new Date());
const data = planDateRecord.get(formatDate);
const className = getClassByStatus(date, data?.status ?? null, currentDate);

const onChange = (value: Value, event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
console.log(value);
};
return (
<DayBird
key={`${date}`}
className={cls(className)}
cursor={className === 'after-today' ? 'default' : 'pointer'}
>
<p className={cls(className)}>{dayjs(date).format('DD')}</p>
</DayBird>
);
},
[planDateRecord, currentDate]
);

const tileDisabled: TileDisabledFunc = useCallback(
({ date }) => getClassByStatus(date, null, currentDate) === 'after-today',
[currentDate]
);

return (
<div className="Calendar">
<div className="Calendar__container">
<main className="Calendar__container__content">
<ReactCalendar onChange={onChange} value={value} />
</main>
</div>
</div>
<ReactCalendar
value={currentDate}
onClickDay={onChange}
calendarType="gregory"
formatDay={(_, date) => dayjs(date).format('D')}
goToRangeStartOnSelect={false}
maxDate={new Date(dayjs().add(1, 'year').format('YYYY-MM-DD'))}
showNavigation={false}
tileContent={tileContent}
tileDisabled={tileDisabled}
activeStartDate={currentDate}
/>
);
};
Original file line number Diff line number Diff line change
@@ -1,53 +1,36 @@
import { TPlanRecord } from '@api/types';
import { DayBird } from '@components/common/DayBird';
import { cls } from '@utils/classname';
import { DAY_OF_WEEK } from '@constants/plan';
import { cls, getClassByStatus } from '@utils/classname';
import dayjs from 'dayjs';
import { useCallback } from 'react';
import styled from 'styled-components';

type TProps = {
record: TPlanRecord[];
currentDate: Date;
};

const dayOfWeek = ['일', '월', '화', '수', '목', '금', '토'];

export const CustomCalendar = ({ record }: TProps) => {
const colorName = useCallback((record: TPlanRecord) => {
const today = new Date();
const recordDate = new Date(record.createdAt);

if (recordDate.getMonth() > today.getMonth()) {
return 'after-today';
}

if (recordDate.getDate() === today.getDate()) {
return 'today';
}

if (record.status === null) {
return 'before';
}

return record.status;
}, []);

export const WeekCalendar = ({ record, currentDate }: TProps) => {
return (
<Wrap>
<FlexBox>
{dayOfWeek.map((day) => (
{DAY_OF_WEEK.map((day) => (
<DayOfWeekWrap key={`${day}`}>
<p>{day}</p>
</DayOfWeekWrap>
))}
</FlexBox>
<FlexBox>
{record.map((weekRecord) => (
<DayBird key={`${weekRecord.createdAt}`} className={cls(colorName(weekRecord))}>
<Text className={cls(colorName(weekRecord))}>
{dayjs(weekRecord.createdAt).format('DD')}
</Text>
</DayBird>
))}
{record.map((weekRecord) => {
const date = new Date(weekRecord.createdAt);
const className = getClassByStatus(date, weekRecord.status, currentDate);

return (
<DayBird key={`${weekRecord.createdAt}`} className={cls(className)}>
<Text className={cls(className)}>{dayjs(weekRecord.createdAt).format('DD')}</Text>
</DayBird>
);
})}
</FlexBox>
</Wrap>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Calendar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { Calendar } from './Calendar';
export { CustomCalendar } from './CustomCalendar';
export { WeekCalendar } from './WeekCalendar';
19 changes: 10 additions & 9 deletions src/components/common/Loadable/Loadable.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { LoadingTemplate } from '@components/templates/LoadingTemplate';
import { LazyExoticComponent, Suspense } from 'react';

export const Loadable =
(
Component: LazyExoticComponent<() => JSX.Element>,
fallback: JSX.Element = <div>로딩중...</div>
) =>
() => (
<Suspense fallback={fallback}>
<Component />
</Suspense>
);
(
Component: LazyExoticComponent<() => JSX.Element>,
fallback: JSX.Element = <LoadingTemplate />
) =>
() => (
<Suspense fallback={fallback}>
<Component />
</Suspense>
);
3 changes: 3 additions & 0 deletions src/components/common/Loading/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const Loading = () => {
return <div>로딩중이에요.</div>;
};
1 change: 1 addition & 0 deletions src/components/common/Loading/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Loading } from './Loading';
36 changes: 24 additions & 12 deletions src/components/common/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,38 @@ export const Navigation = () => {

return (
<NavWrap>
<NavLink to="/" className={cls({ selected: /^\/$|^\/calendar$/g.test(pathname) })}>
<IconHome />
<span></span>
</NavLink>
<NavLink to="/search" className={cls({ selected: pathname === '/search' })}>
<IconSearch />
<span>검색</span>
</NavLink>
<NavLink to="/mypage" className={cls({ selected: pathname === '/mypage' })}>
<IconMyPage />
<span>마이페이지</span>
</NavLink>
<NavInner>
<NavLink to="/" className={cls({ selected: /^\/$|^\/calendar$/g.test(pathname) })}>
<IconHome />
<span></span>
</NavLink>
<NavLink to="/search" className={cls({ selected: pathname === '/search' })}>
<IconSearch />
<span>검색</span>
</NavLink>
<NavLink to="/mypage" className={cls({ selected: pathname === '/mypage' })}>
<IconMyPage />
<span>마이페이지</span>
</NavLink>
</NavInner>
</NavWrap>
);
};

const NavWrap = styled.nav`
flex: 0 0 70px;
width: 100%;
background-color: white;
display: flex;
justify-content: center;
align-items: flex-start;
`;

const NavInner = styled.div`
width: 100%;
max-width: 368px;
height: 100%;
border-top: 1px solid ${({ theme }) => theme.colors.basic};
padding-top: 10px;
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/ProgressBar/ProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ const StyledProgress = styled.progress`
}
&::-moz-progress-bar {
background-color: #cbd2fc;
background-color: ${({ theme }) => theme.colors.subYellow};
border-radius: 20px;
border: none;
}
&::-webkit-progress-value {
background-color: #cbd2fc;
background-color: ${({ theme }) => theme.colors.subYellow};
border-radius: 20px;
border: none;
}
Expand Down
Loading

0 comments on commit f976463

Please sign in to comment.