diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index af84d656..51e88a92 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -24,13 +24,15 @@ jobs: version: 6.10.0 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "18" cache: "pnpm" - name: Install Dependencies - run: pnpm install + run: | + pnpm install - name: Build - run: pnpm build + run: | + pnpm build diff --git a/apps/web/README.md b/apps/web/README.md index 7c8e56d8..c1faade7 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -1 +1,2 @@ ![Group 110](https://github.com/depromeet/layer/assets/19422885/b85ee18d-ca94-4f20-9058-c03e41188291) +. diff --git a/apps/web/package.json b/apps/web/package.json index 958471b7..f474af3d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -81,7 +81,7 @@ "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.6", - "typescript": "^5.2.2", + "typescript": "~5.3.3", "vite": "^5.2.0", "vite-plugin-svgr": "^4.2.0" } diff --git a/apps/web/src/assets/svgs/calendar/ic_next_chevron.svg b/apps/web/src/assets/svgs/calendar/ic_next_chevron.svg index 64f89a86..f3a22033 100644 --- a/apps/web/src/assets/svgs/calendar/ic_next_chevron.svg +++ b/apps/web/src/assets/svgs/calendar/ic_next_chevron.svg @@ -1,3 +1,3 @@ - + diff --git a/apps/web/src/assets/svgs/calendar/ic_prev_chevron.svg b/apps/web/src/assets/svgs/calendar/ic_prev_chevron.svg index 4f8b4ee7..c26bcb62 100644 --- a/apps/web/src/assets/svgs/calendar/ic_prev_chevron.svg +++ b/apps/web/src/assets/svgs/calendar/ic_prev_chevron.svg @@ -1,3 +1,3 @@ - + diff --git a/apps/web/src/component/common/dateTimePicker/Calendar.tsx b/apps/web/src/component/common/dateTimePicker/Calendar.tsx index 657a7c09..13186cfc 100644 --- a/apps/web/src/component/common/dateTimePicker/Calendar.tsx +++ b/apps/web/src/component/common/dateTimePicker/Calendar.tsx @@ -2,6 +2,7 @@ import ReactCalendar from "react-calendar"; import type { CalendarProps as ReactCalendarProps } from "react-calendar"; import { Icon } from "@/component/common/Icon"; +import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; type CalendarProps = ReactCalendarProps; @@ -10,8 +11,8 @@ export function Calendar({ ...props }: CalendarProps) { new Intl.DateTimeFormat("en", { day: "numeric" }).format(date)} - prevLabel={} - nextLabel={} + prevLabel={} + nextLabel={} {...props} /> ); diff --git a/apps/web/src/component/common/dateTimePicker/TimePicker.tsx b/apps/web/src/component/common/dateTimePicker/TimePicker.tsx index f004632e..82f40a45 100644 --- a/apps/web/src/component/common/dateTimePicker/TimePicker.tsx +++ b/apps/web/src/component/common/dateTimePicker/TimePicker.tsx @@ -1,5 +1,5 @@ import { css } from "@emotion/react"; -import { forwardRef } from "react"; +import { forwardRef, useEffect, useRef } from "react"; import { TIME_24 } from "@/component/common/dateTimePicker/time.const"; import { Radio, RadioButtonGroup } from "@/component/common/radioButton"; @@ -12,33 +12,93 @@ type TimePickerProps = { }; export const TimePicker = forwardRef(function ({ radioControl }, ref) { const { curTab, tabs, selectTab } = useTabs(["오전", "오후"] as const); + const radioButtonsContainerRef = useRef(null); + + const pmFirstItemRef = useRef(null); + const amFirstItemRef = useRef(null); + + /** + * 탭을 클릭해 scrollIntoView가 작동 중인지에 대한 상태 + */ + const isScrollingIntoView = useRef(false); + + useEffect(() => { + const checkPmInView = () => { + if (isScrollingIntoView.current) { + return; + } + + const pmFirstClientRect = pmFirstItemRef.current?.getBoundingClientRect(); + if (pmFirstClientRect && pmFirstClientRect.x < 200) { + selectTab("오후"); + } else { + selectTab("오전"); + } + }; + + const containerRef = radioButtonsContainerRef.current; + containerRef?.addEventListener("scroll", checkPmInView); + + return () => { + containerRef?.removeEventListener("scroll", checkPmInView); + }; + }, [selectTab]); + return (
- - - {curTab === "오전" && - TIME_24.slice(0, 12).map((time, index) => { + { + selectTab(tab); + isScrollingIntoView.current = true; + + if (tab === "오후") { + pmFirstItemRef.current?.scrollIntoView({ behavior: "smooth", inline: "start" }); + } + if (tab === "오전") { + amFirstItemRef.current?.scrollIntoView({ behavior: "smooth", inline: "start" }); + } + + setTimeout(() => { + isScrollingIntoView.current = false; + }, 1000); + }} + /> +
+ + {TIME_24.slice(0, 13).map((time, index) => { return ( - - {time} + + {time} ); })} - {curTab === "오후" && - TIME_24.slice(12).map((time, index) => { + {TIME_24.slice(13).map((time, index) => { return ( - - {`${Number(time.split(":")[0]) - 12}:00`} + + {time} ); })} - + +
); }); diff --git a/apps/web/src/component/common/dateTimePicker/time.const.ts b/apps/web/src/component/common/dateTimePicker/time.const.ts index 7a4c25a1..fe92cc00 100644 --- a/apps/web/src/component/common/dateTimePicker/time.const.ts +++ b/apps/web/src/component/common/dateTimePicker/time.const.ts @@ -1 +1 @@ -export const TIME_24 = Array.from({ length: 24 }, (_, i) => `${i + 1}:00`); +export const TIME_24 = Array.from({ length: 25 }, (_, i) => `${i === 0 ? "00" : i}:00`); diff --git a/apps/web/src/component/common/radioButton/Radio.tsx b/apps/web/src/component/common/radioButton/Radio.tsx index 8395fdba..fc42522e 100644 --- a/apps/web/src/component/common/radioButton/Radio.tsx +++ b/apps/web/src/component/common/radioButton/Radio.tsx @@ -1,34 +1,42 @@ import { css } from "@emotion/react"; -import { useContext } from "react"; +import { forwardRef, useContext } from "react"; import { RadioContext } from "./RadioButtonGroup"; import { Typography } from "@/component/common/typography"; -import { DESIGN_SYSTEM_COLOR } from "@/style/variable"; +import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; type RadioProps = { value: string; children: React.ReactNode; + rounded?: "sm" | "lg"; } & Omit, "checked">; -export function Radio({ value, children, ...props }: RadioProps) { +export const Radio = forwardRef(function ({ value, rounded = "sm", children, ...props }, ref) { const radioContext = useContext(RadioContext); + + const STYLE_MAP = { + borderRadius: { + sm: "0.6rem", + lg: "0.8rem", + }, + } as const; + return ( ); -} +}); + +Radio.displayName = "Radio"; diff --git a/apps/web/src/component/common/radioButton/RadioButtonGroup.tsx b/apps/web/src/component/common/radioButton/RadioButtonGroup.tsx index a9c63606..39b3e211 100644 --- a/apps/web/src/component/common/radioButton/RadioButtonGroup.tsx +++ b/apps/web/src/component/common/radioButton/RadioButtonGroup.tsx @@ -1,11 +1,10 @@ -import { css, Interpolation, Theme } from "@emotion/react"; +import { css, SerializedStyles } from "@emotion/react"; import { createContext, forwardRef } from "react"; export type RadioContextState = { radioName: string; isChecked: (value: string) => boolean; onChange: (value: string) => void; - radioStyles?: Interpolation; }; export const RadioContext = createContext(undefined); @@ -14,11 +13,11 @@ type RadioButtonGroupProps = { children: React.ReactNode; direction?: "row" | "column"; gap?: number; - styles?: Interpolation; + styles?: SerializedStyles; } & RadioContextState; export const RadioButtonGroup = forwardRef(function ( - { children, styles, gap = 0.8, direction = "row", ...props }, + { children, gap = 0.8, direction = "row", styles, radioName, isChecked, onChange }, ref, ) { return ( @@ -34,7 +33,7 @@ export const RadioButtonGroup = forwardRef - {children} + {children} ); }); diff --git a/apps/web/src/component/retrospectCreate/steps/DueDate.tsx b/apps/web/src/component/retrospectCreate/steps/DueDate.tsx index 941cf847..816948f0 100644 --- a/apps/web/src/component/retrospectCreate/steps/DueDate.tsx +++ b/apps/web/src/component/retrospectCreate/steps/DueDate.tsx @@ -1,3 +1,4 @@ +import { css } from "@emotion/react"; import { useSetAtom } from "jotai"; import { useContext, useState } from "react"; @@ -5,18 +6,18 @@ import { RetrospectCreateContext } from "@/app/retrospectCreate/RetrospectCreate import { ButtonProvider } from "@/component/common/button"; import { Header } from "@/component/common/header"; import { DateTimeInput } from "@/component/common/input/DateTimeInput"; +import { Radio, RadioButtonGroup } from "@/component/common/radioButton"; import { Spacing } from "@/component/common/Spacing"; +import { useRadioButton } from "@/hooks/useRadioButton"; import { retrospectCreateAtom } from "@/store/retrospect/retrospectCreate"; export function DueDate() { const { goNext, isMutatePending } = useContext(RetrospectCreateContext); const setRetroCreateData = useSetAtom(retrospectCreateAtom); const [selectedDateTime, setSelectedDateTime] = useState(); + const { selectedValue, isChecked, onChange } = useRadioButton(); const handleDataSave = () => { - if (!selectedDateTime) { - return; - } setRetroCreateData((prev) => ({ ...prev, deadline: selectedDateTime })); }; @@ -29,13 +30,35 @@ export function DueDate() { <>
- { - setSelectedDateTime(value); - }} - /> + + + 마감일 미지정 + + + 마감일 지정 + + + {selectedValue === "has-duedate-pos" && ( + { + setSelectedDateTime(value); + }} + /> + )} - + 다음 diff --git a/apps/web/src/hooks/useRadioButton.ts b/apps/web/src/hooks/useRadioButton.ts index 934be9f4..eff25d20 100644 --- a/apps/web/src/hooks/useRadioButton.ts +++ b/apps/web/src/hooks/useRadioButton.ts @@ -1,6 +1,7 @@ import { useState } from "react"; export const useRadioButton = (defaultValue?: string) => { + //FIXME - value를 제네릭 타입으로 수정하기 const [selectedValue, setSelectedValue] = useState(defaultValue); const isChecked = (value: string) => selectedValue === value; const onChange = (value: string) => setSelectedValue(value); diff --git a/apps/web/src/lib/provider/mix-pannel-provider/event.type.ts b/apps/web/src/lib/provider/mix-pannel-provider/event.type.ts index 66a0fdc0..712c23c4 100644 --- a/apps/web/src/lib/provider/mix-pannel-provider/event.type.ts +++ b/apps/web/src/lib/provider/mix-pannel-provider/event.type.ts @@ -18,7 +18,7 @@ type EVENTS_TO_PROPERTIES = { templateId: number; spaceId: number; title: string; - deadline: string; + deadline?: string; }; TEMPLATE_RECOMMEND: Omit; diff --git a/apps/web/src/types/retrospectCreate/index.ts b/apps/web/src/types/retrospectCreate/index.ts index be851f29..6cd278ff 100644 --- a/apps/web/src/types/retrospectCreate/index.ts +++ b/apps/web/src/types/retrospectCreate/index.ts @@ -11,7 +11,7 @@ export type RetrospectCreateReq = { title: string; introduction?: string; questions: Questions; - deadline: string; + deadline?: string; /** * 기본 템플릿을 수정한 경우 true */ diff --git a/package.json b/package.json index 886cbeb4..2a2bd919 100644 --- a/package.json +++ b/package.json @@ -11,20 +11,6 @@ "build:app": "pnpm build --filter=\"...{./apps/app}\"", "build:web": "pnpm build --filter=\"...{./apps/web}\"" }, - "devDependencies": { - "typescript": "^5.5.4" - }, - "workspaces": [ - "packages/*", - "apps/*" - ], - "pnpm": { - "peerDependencyRules": { - "ignoreMissing": [ - "typescript" - ] - } - }, "dependencies": { "lerna": "^8.1.8" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d30d1a8..84192617 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,10 +11,6 @@ importers: lerna: specifier: ^8.1.8 version: 8.1.8 - devDependencies: - typescript: - specifier: ^5.5.4 - version: 5.6.2 apps/mobile: dependencies: @@ -393,7 +389,7 @@ importers: specifier: ^0.4.6 version: 0.4.7(eslint@8.57.0) typescript: - specifier: ^5.2.2 + specifier: ~5.3.3 version: 5.3.3 vite: specifier: ^5.2.0 @@ -16207,9 +16203,6 @@ packages: engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' - peerDependenciesMeta: - typescript: - optional: true dependencies: typescript: 5.3.3 dev: true @@ -16385,6 +16378,7 @@ packages: resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} hasBin: true + dev: false /ua-parser-js@1.0.38: resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bb66209e..481b43b9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,4 @@ packages: - - 'packages/*' - - 'apps/*' - - docs \ No newline at end of file + - "packages/*" + - "apps/*" + - docs