-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(onboarding-flow): implement onboarding functionality
- Loading branch information
1 parent
da36774
commit d0105fd
Showing
5 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 165 additions & 0 deletions
165
src/components/ModalsContainer/OnboardingFlow/GraphDetailsStep/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import { Button } from '@mui/material' | ||
import { FC, useEffect } from 'react' | ||
import { useFormContext } from 'react-hook-form' | ||
import { MdError } from 'react-icons/md' | ||
import styled from 'styled-components' | ||
import { noSpacePattern } from '~/components/AddItemModal/SourceTypeStep/constants' | ||
import { Flex } from '~/components/common/Flex' | ||
import { Text } from '~/components/common/Text' | ||
import { TextInput } from '~/components/common/TextInput' | ||
import { requiredRule } from '~/constants' | ||
import { colors } from '~/utils' | ||
|
||
type Props = { | ||
onSubmit: () => void | ||
error?: string | ||
} | ||
|
||
export const GraphDetailsStep: FC<Props> = ({ onSubmit, error }) => { | ||
const { | ||
formState: { isSubmitting }, | ||
watch, | ||
} = useFormContext() | ||
|
||
const title = watch('title') | ||
const description = watch('description') | ||
|
||
const isFormValid = !!title?.trim() && !!description?.trim() | ||
|
||
useEffect(() => { | ||
const titleInput = document.getElementById('graph-title') as HTMLInputElement | ||
|
||
if (titleInput) { | ||
titleInput.focus() | ||
} | ||
}, []) | ||
|
||
return ( | ||
<Flex> | ||
<Flex align="center" direction="column" justify="center"> | ||
<StyledText>Welcome to SecondBrain!</StyledText> | ||
<StyledSubText>Set a name and short description for your graph.</StyledSubText> | ||
</Flex> | ||
|
||
<StyledWrapper> | ||
<Flex className="input__wrapper"> | ||
<TextInput | ||
id="graph-title" | ||
label="Title" | ||
maxLength={50} | ||
name="title" | ||
placeholder="Type graph title here..." | ||
rules={{ | ||
...requiredRule, | ||
pattern: { | ||
message: 'No leading whitespace allowed', | ||
value: noSpacePattern, | ||
}, | ||
}} | ||
/> | ||
<TextInput | ||
id="graph-description" | ||
label="Description" | ||
maxLength={100} | ||
name="description" | ||
placeholder="Type graph description here..." | ||
rules={{ | ||
...requiredRule, | ||
pattern: { | ||
message: 'No leading whitespace allowed', | ||
value: noSpacePattern, | ||
}, | ||
}} | ||
/> | ||
</Flex> | ||
</StyledWrapper> | ||
|
||
<Flex mt={10}> | ||
<Button | ||
color="secondary" | ||
disabled={isSubmitting || !!error || !isFormValid} | ||
onClick={onSubmit} | ||
size="large" | ||
variant="contained" | ||
> | ||
Confirm | ||
</Button> | ||
</Flex> | ||
{error ? ( | ||
<StyledError> | ||
<StyledErrorText> | ||
<MdError className="errorIcon" /> | ||
<span>{error}</span> | ||
</StyledErrorText> | ||
</StyledError> | ||
) : null} | ||
</Flex> | ||
) | ||
} | ||
|
||
const StyledText = styled(Text)` | ||
font-size: 22px; | ||
font-weight: 600; | ||
font-family: 'Barlow'; | ||
text-align: center; | ||
margin-bottom: 10px; | ||
` | ||
|
||
const StyledSubText = styled(Text)` | ||
font-size: 14px; | ||
font-family: 'Barlow'; | ||
margin-bottom: 20px; | ||
` | ||
|
||
const StyledWrapper = styled(Flex)` | ||
width: 100%; | ||
display: flex; | ||
justify-content: center; | ||
gap: 10px; | ||
margin: 0 0 15px 0; | ||
.input__wrapper { | ||
display: flex; | ||
gap: 23px; | ||
max-height: 225px; | ||
overflow-y: auto; | ||
padding-right: 20px; | ||
width: calc(100% + 20px); | ||
} | ||
` | ||
|
||
const StyledErrorText = styled(Flex)` | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
justify-content: center; | ||
gap: 2px; | ||
.errorIcon { | ||
display: block; | ||
font-size: 13px; | ||
min-height: 13px; | ||
min-width: 13px; | ||
} | ||
span { | ||
display: -webkit-box; | ||
-webkit-line-clamp: 1; | ||
-webkit-box-orient: vertical; | ||
overflow: hidden; | ||
white-space: normal; | ||
letter-spacing: 0.2px; | ||
padding-left: 4px; | ||
font-size: 13px; | ||
font-family: Barlow; | ||
line-height: 18px; | ||
} | ||
` | ||
|
||
const StyledError = styled(Flex)` | ||
display: flex; | ||
align-items: center; | ||
color: ${colors.primaryRed}; | ||
position: relative; | ||
margin-top: 20px; | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { useEffect, useState } from 'react' | ||
import { FormProvider, useForm } from 'react-hook-form' | ||
import { SuccessNotify } from '~/components/common/SuccessToast' | ||
import { BaseModal } from '~/components/Modal' | ||
import { NODE_ADD_ERROR } from '~/constants' | ||
import { postAboutData, TAboutParams } from '~/network/fetchSourcesData' | ||
import { useModal } from '~/stores/useModalStore' | ||
import { GraphDetailsStep } from './GraphDetailsStep' | ||
|
||
export type FormData = { | ||
title: string | ||
description: string | ||
} | ||
|
||
export const OnboardingModal = () => { | ||
const { close, visible } = useModal('onboardingFlow') | ||
const form = useForm<FormData>({ mode: 'onChange' }) | ||
const { reset } = form | ||
const [error, setError] = useState<string>('') | ||
|
||
useEffect(() => { | ||
if (!visible) { | ||
reset() | ||
setError('') | ||
} | ||
}, [visible, reset]) | ||
|
||
const submitGraphDetails = async (data: TAboutParams, onSuccess: () => void, onError: (error: string) => void) => { | ||
try { | ||
const res = (await postAboutData(data)) as Awaited<{ status: string }> | ||
|
||
if (res.status === 'success') { | ||
SuccessNotify('Graph details saved') | ||
onSuccess() | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
} catch (err: any) { | ||
let errorMessage = NODE_ADD_ERROR | ||
|
||
if (err?.status === 400) { | ||
const errorRes = await err.json() | ||
|
||
errorMessage = errorRes.errorCode || errorRes?.status || NODE_ADD_ERROR | ||
} else if (err instanceof Error) { | ||
errorMessage = err.message | ||
} | ||
|
||
onError(String(errorMessage)) | ||
} | ||
} | ||
|
||
const onSubmit = form.handleSubmit(async (data) => { | ||
await submitGraphDetails( | ||
data, | ||
() => { | ||
close() | ||
}, | ||
setError, | ||
) | ||
}) | ||
|
||
return ( | ||
<BaseModal id="onboardingFlow" kind="small" onClose={close} preventOutsideClose> | ||
<FormProvider {...form}> | ||
<form id="onboardingFlow-form" onSubmit={onSubmit}> | ||
<GraphDetailsStep error={error} onSubmit={onSubmit} /> | ||
</form> | ||
</FormProvider> | ||
</BaseModal> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters