Skip to content

Commit

Permalink
Merge pull request #365 from depromeet/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
klmhyeonwoo authored Sep 10, 2024
2 parents b7ad3db + 968e44e commit b6bbad4
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 55 deletions.
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@layer/mobile",
"main": "expo-router/entry",
"types": "./bridge/native.ts",
"version": "1.0.3",
"version": "1.0.2",
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@layer/web",
"private": true,
"version": "1.0.3",
"version": "1.0.2",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/assets/svgs/calendar/ic_next_chevron.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/web/src/assets/svgs/calendar/ic_prev_chevron.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions apps/web/src/component/common/dateTimePicker/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -10,8 +11,8 @@ export function Calendar({ ...props }: CalendarProps) {
<ReactCalendar
calendarType={"gregory"}
formatDay={(_, date) => new Intl.DateTimeFormat("en", { day: "numeric" }).format(date)}
prevLabel={<Icon icon={"ic_prev_chevron"} style={{ cursor: "inherit" }} />}
nextLabel={<Icon icon={"ic_next_chevron"} style={{ cursor: "inherit" }} />}
prevLabel={<Icon icon={"ic_prev_chevron"} color={DESIGN_TOKEN_COLOR.gray900} style={{ cursor: "inherit" }} />}
nextLabel={<Icon icon={"ic_next_chevron"} color={DESIGN_TOKEN_COLOR.gray900} style={{ cursor: "inherit" }} />}
{...props}
/>
);
Expand Down
84 changes: 72 additions & 12 deletions apps/web/src/component/common/dateTimePicker/TimePicker.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -12,33 +12,93 @@ type TimePickerProps = {
};
export const TimePicker = forwardRef<HTMLDivElement, TimePickerProps>(function ({ radioControl }, ref) {
const { curTab, tabs, selectTab } = useTabs(["오전", "오후"] as const);
const radioButtonsContainerRef = useRef<HTMLDivElement>(null);

const pmFirstItemRef = useRef<HTMLLabelElement>(null);
const amFirstItemRef = useRef<HTMLLabelElement>(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 (
<div
ref={ref}
css={css`
display: flex;
flex-direction: column;
gap: 2.4rem;
`}
>
<AmPmTabs tabs={tabs} curTab={curTab} selectTab={selectTab} />
<RadioButtonGroup isChecked={radioControl.isTimeChecked} onChange={radioControl.onTimeChange} radioName={"회고 마감 시간"} ref={ref}>
{curTab === "오전" &&
TIME_24.slice(0, 12).map((time, index) => {
<AmPmTabs
tabs={tabs}
curTab={curTab}
selectTab={(tab) => {
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);
}}
/>
<div
css={css`
display: flex;
`}
>
<RadioButtonGroup
isChecked={radioControl.isTimeChecked}
onChange={radioControl.onTimeChange}
radioName={"회고 마감 시간"}
ref={radioButtonsContainerRef}
>
{TIME_24.slice(0, 13).map((time, index) => {
return (
<Radio key={index} value={time}>
{time}
<Radio ref={index === 0 ? amFirstItemRef : null} value={time} key={index}>
<span>{time}</span>
</Radio>
);
})}
{curTab === "오후" &&
TIME_24.slice(12).map((time, index) => {
{TIME_24.slice(13).map((time, index) => {
return (
<Radio key={index} value={time}>
{`${Number(time.split(":")[0]) - 12}:00`}
<Radio ref={index === 0 ? pmFirstItemRef : null} value={time} key={index}>
<span>{time}</span>
</Radio>
);
})}
</RadioButtonGroup>
</RadioButtonGroup>
</div>
</div>
);
});
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/component/common/dateTimePicker/time.const.ts
Original file line number Diff line number Diff line change
@@ -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`);
30 changes: 20 additions & 10 deletions apps/web/src/component/common/radioButton/Radio.tsx
Original file line number Diff line number Diff line change
@@ -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<React.InputHTMLAttributes<HTMLInputElement>, "checked">;

export function Radio({ value, children, ...props }: RadioProps) {
export const Radio = forwardRef<HTMLLabelElement, RadioProps>(function ({ value, rounded = "sm", children, ...props }, ref) {
const radioContext = useContext(RadioContext);

const STYLE_MAP = {
borderRadius: {
sm: "0.6rem",
lg: "0.8rem",
},
} as const;

return (
<label
ref={ref}
htmlFor={value}
css={css`
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
width: fit-content;
padding: 1.2rem 1.6rem;
border-radius: 0.6rem;
background-color: ${radioContext?.isChecked(value) ? DESIGN_SYSTEM_COLOR.theme3 : DESIGN_SYSTEM_COLOR.lightGrey2};
border-radius: ${STYLE_MAP.borderRadius[rounded]};
background-color: ${radioContext?.isChecked(value) ? DESIGN_TOKEN_COLOR.blue600 : DESIGN_TOKEN_COLOR.gray100};
transition: 0.2s all;
cursor: pointer;
`}
>
<Typography color={radioContext?.isChecked(value) ? "white" : "darkGrayText"} variant={"body16Medium"}>
<Typography color={radioContext?.isChecked(value) ? "gray00" : "gray800"} variant={"body16Medium"}>
{children}
</Typography>
<input
Expand All @@ -46,4 +54,6 @@ export function Radio({ value, children, ...props }: RadioProps) {
/>
</label>
);
}
});

Radio.displayName = "Radio";
Original file line number Diff line number Diff line change
@@ -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<Theme>;
};

export const RadioContext = createContext<RadioContextState | undefined>(undefined);
Expand All @@ -14,11 +13,11 @@ type RadioButtonGroupProps = {
children: React.ReactNode;
direction?: "row" | "column";
gap?: number;
styles?: Interpolation<Theme>;
styles?: SerializedStyles;
} & RadioContextState;

export const RadioButtonGroup = forwardRef<HTMLDivElement, RadioButtonGroupProps>(function (
{ children, styles, gap = 0.8, direction = "row", ...props },
{ children, gap = 0.8, direction = "row", styles, radioName, isChecked, onChange },
ref,
) {
return (
Expand All @@ -34,7 +33,7 @@ export const RadioButtonGroup = forwardRef<HTMLDivElement, RadioButtonGroupProps
styles,
]}
>
<RadioContext.Provider value={props}>{children}</RadioContext.Provider>
<RadioContext.Provider value={{ radioName, isChecked, onChange }}>{children}</RadioContext.Provider>
</div>
);
});
Expand Down
41 changes: 32 additions & 9 deletions apps/web/src/component/retrospectCreate/steps/DueDate.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { css } from "@emotion/react";
import { useSetAtom } from "jotai";
import { useContext, useState } from "react";

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<string>();
const { selectedValue, isChecked, onChange } = useRadioButton();

const handleDataSave = () => {
if (!selectedDateTime) {
return;
}
setRetroCreateData((prev) => ({ ...prev, deadline: selectedDateTime }));
};

Expand All @@ -29,13 +30,35 @@ export function DueDate() {
<>
<Header title={"회고는\n언제까지 작성할까요?"} />
<Spacing size={4} />
<DateTimeInput
onValueChange={(value) => {
setSelectedDateTime(value);
}}
/>
<RadioButtonGroup
radioName="has-duedate"
onChange={onChange}
isChecked={isChecked}
direction={"column"}
styles={css`
margin-bottom: 1.2rem;
`}
>
<Radio value={"has-duedate-neg"} rounded="lg">
마감일 미지정
</Radio>
<Radio value={"has-duedate-pos"} rounded="lg">
마감일 지정
</Radio>
</RadioButtonGroup>
{selectedValue === "has-duedate-pos" && (
<DateTimeInput
onValueChange={(value) => {
setSelectedDateTime(value);
}}
/>
)}
<ButtonProvider isProgress={isMutatePending}>
<ButtonProvider.Primary onClick={onNext} disabled={!selectedDateTime} type="submit">
<ButtonProvider.Primary
onClick={onNext}
disabled={(selectedValue === "has-duedate-pos" && !selectedDateTime) || !selectedValue}
type="submit"
>
다음
</ButtonProvider.Primary>
</ButtonProvider>
Expand Down
17 changes: 11 additions & 6 deletions apps/web/src/component/space/view/ActionItemListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Button, ButtonProvider } from "@/component/common/button";
import { Icon } from "@/component/common/Icon";
import { TextArea } from "@/component/common/input";
import { SelectBox } from "@/component/common/SelectBox";
import { SelectBoxType } from "@/component/common/SelectBox/SelectBox.tsx";
import { Spacing } from "@/component/common/Spacing";
import { Typography } from "@/component/common/typography";
import { useCreateActionItem } from "@/hooks/api/actionItem/useCreateActionItem";
Expand All @@ -32,11 +33,15 @@ type ActionItemProps = {
};

export function ActionItemListView({ isPossibleMake, teamActionList, spaceId, leaderId, restrospectArr = [] }: ActionItemListViewProps) {
const retrospectInfo = restrospectArr.map((item) => ({
retrospectId: item.retrospectId,
retrospectTitle: item.title,
status: item.retrospectStatus,
}));
const isCompleteRetrospect = restrospectArr.reduce((acc: SelectBoxType["data"], cur) => {
if (cur.retrospectStatus === "DONE")
acc.push({
retrospectId: cur.retrospectId,
retrospectTitle: cur.title,
status: cur.retrospectStatus,
});
return acc;
}, []);

const navigate = useNavigate();
const queryClient = useQueryClient();
Expand Down Expand Up @@ -180,7 +185,7 @@ export function ActionItemListView({ isPossibleMake, teamActionList, spaceId, le
position: relative;
`}
>
<SelectBox data={retrospectInfo} onClick={() => {}} value={retrospect} updateRetroSpectData={updateRetroSpectData} />
<SelectBox data={isCompleteRetrospect} onClick={() => {}} value={retrospect} updateRetroSpectData={updateRetroSpectData} />

<Spacing size={1.5} />
<TextArea value={actionItemValue} onChange={handleInputChange} placeholder={"실행목표를 입력해주세요"} height="14.3rem" />
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/hooks/useRadioButton.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
1 change: 0 additions & 1 deletion apps/web/src/layout/DualToneLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export function DualToneLayout({
background-color: ${DESIGN_SYSTEM_COLOR.themeBackground[bottomTheme]};
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 2rem;
`}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type EVENTS_TO_PROPERTIES = {
templateId: number;
spaceId: number;
title: string;
deadline: string;
deadline?: string;
};

TEMPLATE_RECOMMEND: Omit<RecommendTemplateResponse, "formImageUrl">;
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/types/retrospectCreate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type RetrospectCreateReq = {
title: string;
introduction?: string;
questions: Questions;
deadline: string;
deadline?: string;
/**
* 기본 템플릿을 수정한 경우 true
*/
Expand Down
Loading

0 comments on commit b6bbad4

Please sign in to comment.