diff --git a/app/(app)/project/create.tsx b/app/(app)/project/create.tsx index 790ff14..afae1bf 100644 --- a/app/(app)/project/create.tsx +++ b/app/(app)/project/create.tsx @@ -1,4 +1,4 @@ -import { SimpleLineIcons } from '@expo/vector-icons'; +import { AntDesign } from '@expo/vector-icons'; import type { BottomSheetModal } from '@gorhom/bottom-sheet'; import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet'; import type { DateTimePickerEvent } from '@react-native-community/datetimepicker'; @@ -41,8 +41,6 @@ function Create() { const sheetHeight = useMemo(() => getSize.screenHeight * 0.75, []); - const snapPoints = useMemo(() => [sheetHeight], []); - const openUserListSheet = useCallback(() => { setUserListSheetOpen(true); userListBottomSheetRef.current?.snapToIndex(0); @@ -182,8 +180,8 @@ function Create() { @@ -249,7 +247,7 @@ function Create() { ref={userListBottomSheetRef} index={-1} enablePanDownToClose - snapPoints={snapPoints}> + snapPoints={[sheetHeight]}> {userListSheetOpen && ( - + + + {dayjs(date).format('YYYY-MM-DD')} ); diff --git a/src/components/common/date-input/style.ts b/src/components/common/date-input/style.ts index 9cd772c..3093594 100644 --- a/src/components/common/date-input/style.ts +++ b/src/components/common/date-input/style.ts @@ -10,3 +10,7 @@ export const Container = styled.Pressable` background: ${({ theme }) => theme.color.Background.Normal}; border-radius: 8px; `; + +export const IconBox = styled.View` + ${flexDirectionRowItemsCenter}; +`; diff --git a/src/components/common/icon/radio-icon.tsx b/src/components/common/icon/radio-icon.tsx new file mode 100644 index 0000000..167ea4b --- /dev/null +++ b/src/components/common/icon/radio-icon.tsx @@ -0,0 +1,53 @@ +import Svg, { Circle, Rect } from 'react-native-svg'; + +type Props = { + activeColor: string; + inActiveColor: string; + isChecked: boolean; +}; + +function RadioIcon({ activeColor, inActiveColor, isChecked }: Props) { + if (isChecked) { + return ( + + + + + ); + } else { + return ( + + + + ); + } +} + +export default RadioIcon; diff --git a/src/components/common/input-field/style.ts b/src/components/common/input-field/style.ts index cb3826d..993a87b 100644 --- a/src/components/common/input-field/style.ts +++ b/src/components/common/input-field/style.ts @@ -1,7 +1,7 @@ import styled, { css } from '@emotion/native'; import type { Theme } from '@emotion/react'; -import { flexDirectionRow } from '@/styles/common'; +import { flexDirectionRow, flexDirectionRowItemsCenter } from '@/styles/common'; const errorStyle = (theme: Theme) => css` border-color: ${theme.color.Status.Error}; @@ -24,7 +24,7 @@ export const Container = styled.View<{ }>` ${({ $isError, theme }) => $isError && errorStyle(theme)}; ${({ $disabled, theme }) => $disabled && disabledStyle(theme)}; - ${flexDirectionRow}; + ${flexDirectionRowItemsCenter}; gap: 8px; padding: 18px 16px; background-color: ${({ theme }) => theme.color.Background.Normal}; diff --git a/src/components/questionnaire/QuestionnaireCheckList/index.tsx b/src/components/questionnaire/QuestionnaireCheckList/index.tsx new file mode 100644 index 0000000..356ab29 --- /dev/null +++ b/src/components/questionnaire/QuestionnaireCheckList/index.tsx @@ -0,0 +1,80 @@ +import type { PropsWithChildren } from 'react'; +import { useContext, useState } from 'react'; +import { createContext } from 'react'; +import { memo } from 'react'; + +import RadioIcon from '@/components/common/icon/radio-icon'; +import Typography from '@/components/common/typography'; +import { color } from '@/styles/theme'; +import type { CategoryType } from '@/types/category'; + +import CategoryChip from '../category-chip'; +import * as S from './style'; + +type ItemProps = { + value: string | number; +}; + +const ListContext = createContext<{ + checkValue: string | null | number; + setCheckValue: (newValue: string | null | number) => void; +}>({ + checkValue: null, + setCheckValue: () => null, +}); + +function Item({ children, value }: PropsWithChildren) { + const { checkValue, setCheckValue } = useContext(ListContext); + const isChecked = checkValue === value; + return ( + + {children} + setCheckValue(value)}> + + + + ); +} + +type QuestionnaireCheckListProps = { + title: string; + category: CategoryType; + initialCheckValue?: string | number; +}; + +function CheckList({ + title, + category, + initialCheckValue, + children, +}: PropsWithChildren) { + const [checkValue, setCheckValue] = useState(() => + initialCheckValue ? initialCheckValue : null + ); + return ( + + + + + {title} + + {children} + + + ); +} + +const QuestionnaireCheckList = Object.assign(CheckList, { Item: memo(Item) }); + +export default QuestionnaireCheckList; diff --git a/src/components/questionnaire/QuestionnaireCheckList/style.ts b/src/components/questionnaire/QuestionnaireCheckList/style.ts new file mode 100644 index 0000000..30c59ba --- /dev/null +++ b/src/components/questionnaire/QuestionnaireCheckList/style.ts @@ -0,0 +1,49 @@ +import styled, { css } from '@emotion/native'; +import type { Theme } from '@emotion/react'; + +import { flexDirectionColumn, flexDirectionRowItemsCenter } from '@/styles/common'; + +export const Container = styled.View` + ${flexDirectionColumn}; + gap: 20px; + width: 272px; + padding: 28px 16px; + background: ${({ theme }) => theme.color.Background.Normal}; + border-radius: 13px; +`; + +const inActiveStyle = (theme: Theme) => css` + background: ${theme.color.Background.Normal}; + border: 1px solid ${theme.color.Line.Normal}; +`; + +const activeStyle = (theme: Theme) => css` + background: ${theme.color.Blue['95']}; + border: 1px solid ${theme.color.Primary.Normal}; +`; + +export const ItemContainer = styled.View<{ $isChecked: boolean }>` + ${flexDirectionRowItemsCenter}; + ${({ theme, $isChecked }) => ($isChecked ? activeStyle(theme) : inActiveStyle(theme))}; + justify-content: space-between; + padding: 13px 28px 13px 13px; + border-radius: 7px; +`; + +export const ListContainer = styled.View` + ${flexDirectionColumn}; + gap: 8px; +`; + +export const ItemValue = styled.View` + ${flexDirectionColumn}; +`; + +export const RadioButton = styled.Pressable` + ${flexDirectionRowItemsCenter}; + position: absolute; + top: 0; + right: 0; + height: 100%; + padding: 13px; +`; diff --git a/src/components/questionnaire/QuestionnaireCheckListSkeleton/QuestionnaireCheckListSkeleton.stories.tsx b/src/components/questionnaire/QuestionnaireCheckListSkeleton/QuestionnaireCheckListSkeleton.stories.tsx new file mode 100644 index 0000000..5be4d7a --- /dev/null +++ b/src/components/questionnaire/QuestionnaireCheckListSkeleton/QuestionnaireCheckListSkeleton.stories.tsx @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { View } from 'react-native'; + +import { color } from '@/styles/theme'; + +import QuestionnaireCheckListSkeleton from './'; + +const SkeletonMeta: Meta = { + title: 'questionnaire/QuestionnaireCheckListSkeleton', + component: QuestionnaireCheckListSkeleton, + parameters: { + layout: 'centered', + }, +}; + +export default SkeletonMeta; + +export const Primary: StoryObj = { + render: () => { + return ( + + + + ); + }, +}; diff --git a/src/components/questionnaire/QuestionnaireCheckListSkeleton/index.tsx b/src/components/questionnaire/QuestionnaireCheckListSkeleton/index.tsx new file mode 100644 index 0000000..ba0f344 --- /dev/null +++ b/src/components/questionnaire/QuestionnaireCheckListSkeleton/index.tsx @@ -0,0 +1,44 @@ +import Skeleton from '@/components/common/skeleton'; +import QuestionnaireCheckList from '@/components/questionnaire/QuestionnaireCheckList'; + +import * as S from './style'; + +function SkeletonItem() { + return ( + + + + + ); +} + +function QuestionnaireCheckListSkeleton() { + return ( + + + + + + + + + + + + + + + ); +} + +export default QuestionnaireCheckListSkeleton; diff --git a/src/components/questionnaire/QuestionnaireCheckListSkeleton/style.ts b/src/components/questionnaire/QuestionnaireCheckListSkeleton/style.ts new file mode 100644 index 0000000..db12fb8 --- /dev/null +++ b/src/components/questionnaire/QuestionnaireCheckListSkeleton/style.ts @@ -0,0 +1,8 @@ +import styled from '@emotion/native'; + +import { flexDirectionColumnCenter } from '@/styles/common'; + +export const SkeletonBox = styled.View` + ${flexDirectionColumnCenter}; + gap: 4px; +`; diff --git a/src/components/common/category-chip/CategoryChip.stories.tsx b/src/components/questionnaire/category-chip/CategoryChip.stories.tsx similarity index 92% rename from src/components/common/category-chip/CategoryChip.stories.tsx rename to src/components/questionnaire/category-chip/CategoryChip.stories.tsx index cd2dea4..b98f6b1 100644 --- a/src/components/common/category-chip/CategoryChip.stories.tsx +++ b/src/components/questionnaire/category-chip/CategoryChip.stories.tsx @@ -1,10 +1,10 @@ import type { Meta, StoryObj } from '@storybook/react'; -import CategoryChip from '@/components/common/category-chip/index'; import Storybook from '@/components/common/storybook'; +import CategoryChip from '@/components/questionnaire/category-chip/index'; const CategoryChipMeta: Meta = { - title: 'category/CategoryChip', + title: 'questionnaire/CategoryChip', component: CategoryChip, argTypes: { category: { diff --git a/src/components/common/category-chip/index.tsx b/src/components/questionnaire/category-chip/index.tsx similarity index 100% rename from src/components/common/category-chip/index.tsx rename to src/components/questionnaire/category-chip/index.tsx diff --git a/src/components/common/category-chip/style.ts b/src/components/questionnaire/category-chip/style.ts similarity index 100% rename from src/components/common/category-chip/style.ts rename to src/components/questionnaire/category-chip/style.ts diff --git a/src/components/common/category/Category.stories.tsx b/src/components/questionnaire/category/Category.stories.tsx similarity index 98% rename from src/components/common/category/Category.stories.tsx rename to src/components/questionnaire/category/Category.stories.tsx index caaa85a..b82793a 100644 --- a/src/components/common/category/Category.stories.tsx +++ b/src/components/questionnaire/category/Category.stories.tsx @@ -1,10 +1,10 @@ import type { Meta, StoryObj } from '@storybook/react'; -import Category from '@/components/common/category/index'; import Storybook from '@/components/common/storybook'; +import Category from '@/components/questionnaire/category/index'; const CategoryMeta: Meta = { - title: 'category/Category', + title: 'questionnaire/Category', component: Category, argTypes: { category: { diff --git a/src/components/common/category/index.tsx b/src/components/questionnaire/category/index.tsx similarity index 100% rename from src/components/common/category/index.tsx rename to src/components/questionnaire/category/index.tsx diff --git a/src/components/common/category/style.ts b/src/components/questionnaire/category/style.ts similarity index 95% rename from src/components/common/category/style.ts rename to src/components/questionnaire/category/style.ts index f6393c4..8e5bd52 100644 --- a/src/components/common/category/style.ts +++ b/src/components/questionnaire/category/style.ts @@ -22,6 +22,7 @@ export const Container = styled.View<{ `; export const IconWrapper = styled.View` + ${flexDirectionRowItemsCenter}; width: 24px; height: 24px; `; diff --git a/src/components/review/ProjectChip/index.tsx b/src/components/review/ProjectChip/index.tsx deleted file mode 100644 index bb3e82c..0000000 --- a/src/components/review/ProjectChip/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { PropsWithChildren } from 'react'; -import { memo } from 'react'; - -import Typography from '@/components/common/typography'; - -import * as S from './style'; - -function ProjectChip({ children }: PropsWithChildren) { - return ( - - - {children} - - - ); -} - -export default memo(ProjectChip); diff --git a/src/components/review/ProjectChip/style.ts b/src/components/review/ProjectChip/style.ts deleted file mode 100644 index 6c6d77e..0000000 --- a/src/components/review/ProjectChip/style.ts +++ /dev/null @@ -1,8 +0,0 @@ -import styled from '@emotion/native'; - -export const Container = styled.View` - width: fit-content; - padding: 6px 12px; - background: ${({ theme }) => theme.color.CoolNeutral['98']}; - border-radius: 4px; -`; diff --git a/src/components/review/ReviewCard/index.tsx b/src/components/review/ReviewCard/index.tsx index e1b6d9f..6c1d7cb 100644 --- a/src/components/review/ReviewCard/index.tsx +++ b/src/components/review/ReviewCard/index.tsx @@ -1,7 +1,6 @@ import type { PropsWithChildren } from 'react'; import Typography from '@/components/common/typography'; -import ProjectChip from '@/components/review/ProjectChip'; import * as S from './style'; @@ -29,7 +28,14 @@ type Props = { function Card({ projectName, children }: PropsWithChildren) { return ( - {projectName} + + + {projectName} + + {children} ); diff --git a/src/components/review/ReviewCard/style.ts b/src/components/review/ReviewCard/style.ts index 8a034f6..8590ff2 100644 --- a/src/components/review/ReviewCard/style.ts +++ b/src/components/review/ReviewCard/style.ts @@ -10,6 +10,13 @@ export const Container = styled.View` border-radius: 4px; `; +export const ProjectChip = styled.View` + width: fit-content; + padding: 6px 12px; + background: ${({ theme }) => theme.color.CoolNeutral['98']}; + border-radius: 4px; +`; + export const ContentsBox = styled.View` ${flexDirectionColumn}; gap: 8px;