Skip to content

Commit

Permalink
Refactor/#22 변경된 Onboarding Flow를 반영합니다. (#64)
Browse files Browse the repository at this point in the history
* refactor: 변경된 Onboarding Flow를 반영합니다.

* fix: font 반영이 안되는 현상을 수정합니다.

* fix: test를 위해 useAppOpen으로 분리한다.

* fix: 잘못된 경로명을 변경합니다.
  • Loading branch information
Zero-1016 authored Sep 26, 2024
1 parent 24eecd9 commit e0a0710
Show file tree
Hide file tree
Showing 25 changed files with 329 additions and 157 deletions.
2 changes: 2 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Preview } from '@storybook/react';
import Provider from '../src/components/common/provider';
import { useAppOpen } from '../src/hooks';

const preview: Preview = {
parameters: {
Expand All @@ -13,6 +14,7 @@ const preview: Preview = {
},
decorators: [
(Story) => {
useAppOpen();
return (
<Provider>
<Story />
Expand Down
76 changes: 3 additions & 73 deletions app/(beforeLogin)/onboarding.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,18 @@
import { router } from 'expo-router';
import { useCallback, useState } from 'react';
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated';
import { useCallback } from 'react';

import SolidButton from '@/components/common/button/SolidButton';
import ProgressBar from '@/components/common/progress-bar';
import Typography from '@/components/common/typography';
import { ON_BOARDING } from '@/constants';
import OnboardingScreen from '@/components/onboarding/OnboardingScreen';
import { useOnboarding } from '@/store/useOnboarding';
import { color } from '@/styles/theme';
import { getSize } from '@/utils';

import * as S from './onboarding.styles';

function Onboarding() {
const { checkOnBoarding } = useOnboarding();
const [step, setStep] = useState(0);

const handleStep = () => {
if (step === ON_BOARDING.length - 1) {
return handleLastStep();
}
setStep((prevStep) => prevStep + 1);
};

const handleLastStep = useCallback(() => {
checkOnBoarding();
router.replace('sign-in');
}, [checkOnBoarding]);

const backgroundStyle = useAnimatedStyle(() => ({
position: 'absolute',
flex: 1,
width: getSize.deviceWidth * ON_BOARDING.length,
height: '100%',
left: withTiming(step * -getSize.deviceWidth),
}));

return (
<S.Container>
<Animated.Image
source={require('../../assets/images/onboarding-bg.png')}
style={backgroundStyle}
/>
<S.OnBoardingWrapper>
{ON_BOARDING.map(({ heading, title }, index) => {
return step === index ? (
<S.ContentBox key={index}>
<S.TextWrapper>
<Typography
variant='Heading1'
color={color.Label.Alternative}>
{title}
</Typography>
<Typography
color={color.Label.Normal}
variant='Title3'>
{heading}
</Typography>
</S.TextWrapper>
</S.ContentBox>
) : null;
})}
<ProgressBar
currentStep={step}
stepLength={ON_BOARDING.length}
/>
</S.OnBoardingWrapper>
<S.ButtonBox>
<SolidButton
size='large'
full
onPress={handleStep}>
다음
</SolidButton>
<S.SkipButton onPress={handleLastStep}>
<Typography
variant='Body1/Normal'
color='#878A93'>
건너뛰기
</Typography>
</S.SkipButton>
</S.ButtonBox>
</S.Container>
);
return <OnboardingScreen handleLastStep={handleLastStep} />;
}

export default Onboarding;
25 changes: 3 additions & 22 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
import styled from '@emotion/native';
import { useFonts } from 'expo-font';
import { Slot, SplashScreen } from 'expo-router';
import { useEffect } from 'react';
import { Platform } from 'react-native';

import Provider from '@/components/common/provider';
import { SCREEN_SIZE } from '@/constants';
import { useAppOpen } from '@/hooks';
import { SessionProvider } from '@/store';
import { OnboardingProvider } from '@/store/useOnboarding';

SplashScreen.preventAutoHideAsync();

export default function Root() {
const [loaded, error] = useFonts({
Pretendard: require('../assets/fonts/Pretendard-Regular.otf'),
'Pretendard-Bold': require('../assets/fonts/Pretendard-Bold.otf'),
'Pretendard-SemiBold': require('../assets/fonts/Pretendard-SemiBold.otf'),
'Pretendard-Medium': require('../assets/fonts/Pretendard-Medium.otf'),
});

useEffect(() => {
if (error) throw error;
}, [error]);

if (loaded) {
SplashScreen.hideAsync();
}

if (!loaded) {
return null;
}

useAppOpen();
if (Platform.OS === 'web') {
return (
<Provider>
Expand Down Expand Up @@ -68,7 +49,7 @@ const S = {
`,
Layout: styled.View`
flex: 1;
width: ${SCREEN_SIZE.Web + 'px'};
width: ${SCREEN_SIZE.WEB_WIDTH + 'px'};
height: 100dvh;
`,
};
10 changes: 6 additions & 4 deletions src/components/common/progress-bar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { memo } from 'react';
import type { ViewProps } from 'react-native';
import Animated, { LinearTransition, useAnimatedStyle, withTiming } from 'react-native-reanimated';

import { flexDirectionRowItemsCenter } from '@/styles/common';

type StepBarProps = {
isActive: boolean;
};
Expand All @@ -12,8 +14,8 @@ function StepBar({ isActive }: StepBarProps) {
return {
marginVertical: 'auto',
marginHorizontal: 0,
width: 6,
height: withTiming(isActive ? 16 : 6),
width: withTiming(isActive ? 16 : 6),
height: 6,
backgroundColor: withTiming(isActive ? '#000' : '#00000026', { duration: 500 }),
borderRadius: 30,
alignSelf: 'flex-start',
Expand Down Expand Up @@ -49,10 +51,10 @@ function ProgressBar({ currentStep, stepLength, ...rest }: Props) {
}

export const Container = styled.View`
display: flex;
flex-direction: row;
${flexDirectionRowItemsCenter};
gap: 6px;
height: 16px;
margin: 0 auto 22px;
`;

export default memo(ProgressBar);
6 changes: 6 additions & 0 deletions src/components/home/BusinessCard/BusinessCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ const SkeletonMeta: Meta<typeof BusinessCard> = {
},
description: '스크린에 보이는지 여부를 입력해주세요',
},
onboarding: {
control: {
type: 'boolean',
},
description: '온보딩 화면인지 여부를 입력해주세요',
},
},
parameters: {
layout: 'centered',
Expand Down
19 changes: 11 additions & 8 deletions src/components/home/BusinessCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ type Props = {
name: string;
projectName: string;
review: string;
onboarding?: boolean;
isActive?: boolean;
};

function BusinessCard({ name, review, projectName, isActive = false }: Props) {
function BusinessCard({ name, review, projectName, onboarding = false, isActive = false }: Props) {
const animationStyle = useAnimatedStyle(() => {
return {
display: 'flex',
Expand All @@ -34,10 +35,12 @@ function BusinessCard({ name, review, projectName, isActive = false }: Props) {
});

return (
<S.Container style={shadow[2]}>
<S.Container
$isOnboarding={onboarding}
style={shadow[2]}>
<S.NameBox>
<Typography
variant='Heading1'
variant={onboarding ? 'Headline1' : 'Heading1'}
color={color.Common['0']}
fontWeight='semiBold'>
{name}
Expand All @@ -49,20 +52,20 @@ function BusinessCard({ name, review, projectName, isActive = false }: Props) {
aspectRatio: 1,
borderWidth: 0,
}}
source={{ uri: require('/assets/images/main-mock.png') }}
source={require('../../../../assets/images/main-mock.png')}
resizeMode='center'
width={300}
height={300}
width={onboarding ? 240 : 300}
height={onboarding ? 240 : 300}
/>
<Animated.View style={[animationStyle]}>
<Typography
variant='Body1/Normal'
variant={onboarding ? 'Label1/Reading' : 'Body1/Normal'}
fontWeight='semiBold'
color={color.Common['100']}>
{review}
</Typography>
<Typography
variant='Caption2'
variant={onboarding ? 'Caption2' : 'Caption2'}
color={color.Label.Assistive}>
#{projectName}
</Typography>
Expand Down
4 changes: 2 additions & 2 deletions src/components/home/BusinessCard/style.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import styled from '@emotion/native';

export const Container = styled.View`
export const Container = styled.View<{ $isOnboarding: boolean }>`
position: relative;
width: 300px;
width: ${({ $isOnboarding }) => ($isOnboarding ? '240px' : '300px')};
padding: 74px 0;
background: ${({ theme }) => theme.color.Background.Normal};
border-radius: 17px;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { Meta, StoryObj } from '@storybook/react';
import { View } from 'react-native';

import { SCREEN_SIZE } from '@/constants';

import OnboardingScreen from './';

const ProjectInviteModalMeta: Meta<typeof OnboardingScreen> = {
title: 'screens/Onboarding',
component: OnboardingScreen,
argTypes: {
handleLastStep: {
action: '마지막 페이지로 이동합니다.',
description: '마지막 페이지로 이동될 때 실행되는 함수',
},
},
parameters: {
layout: 'centered',
},
};

export default ProjectInviteModalMeta;

export const Preview: StoryObj<typeof OnboardingScreen> = {
args: {
handleLastStep: () => {
console.log('마지막 페이지로 이동합니다.');
},
},
render: (args) => {
return (
<View style={{ flex: 1, width: SCREEN_SIZE.WEB_WIDTH, height: SCREEN_SIZE.WEB_HEIGHT }}>
<OnboardingScreen {...args} />
</View>
);
},
};
70 changes: 70 additions & 0 deletions src/components/onboarding/OnboardingScreen/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useCallback, useState } from 'react';
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated';

import SolidButton from '@/components/common/button/SolidButton';
import ProgressBar from '@/components/common/progress-bar';
import Typography from '@/components/common/typography';
import OnboardingSection from '@/components/onboarding/OnboardingSection';
import OnboardingTitle, { ON_BOARDING } from '@/components/onboarding/OnboardingTitle';
import { getSize } from '@/utils';

import * as S from './style';

type Props = {
handleLastStep: () => void;
};

function OnboardingScreen({ handleLastStep }: Props) {
const [step, setStep] = useState(0);

const handleStep = useCallback(() => {
if (step === ON_BOARDING.length - 1) {
return handleLastStep();
}
setStep((prevStep) => prevStep + 1);
}, [step]);

const backgroundStyle = useAnimatedStyle(() => ({
position: 'absolute',
flex: 1,
width: getSize.deviceWidth * ON_BOARDING.length,
height: '100%',
left: withTiming(step * -getSize.deviceWidth),
}));

return (
<S.Container>
<Animated.Image
source={require('../../../../assets/images/onboarding-bg.png')}
style={backgroundStyle}
/>
<S.OnBoardingWrapper>
<OnboardingTitle step={step} />
<S.ContentWrapperBox>
<OnboardingSection step={step} />
</S.ContentWrapperBox>
</S.OnBoardingWrapper>
<S.ButtonBox>
<ProgressBar
currentStep={step}
stepLength={ON_BOARDING.length}
/>
<SolidButton
size='large'
full
onPress={handleStep}>
다음
</SolidButton>
<S.SkipButton onPress={handleLastStep}>
<Typography
variant='Body1/Normal'
color='#878A93'>
건너뛰기
</Typography>
</S.SkipButton>
</S.ButtonBox>
</S.Container>
);
}

export default OnboardingScreen;
Loading

0 comments on commit e0a0710

Please sign in to comment.