JoinCircleView: enhance UI/UX with improved messaging, animations, and layout adjustments
This commit is contained in:
@@ -7,9 +7,20 @@ import { useUserProfile } from '../../queries/UserQueries'
|
|||||||
import { useNotification } from '../../service/NotificationProvider'
|
import { useNotification } from '../../service/NotificationProvider'
|
||||||
import { JoinCircle } from '../../utils/Fetcher'
|
import { JoinCircle } from '../../utils/Fetcher'
|
||||||
import { clearPendingInvite, setPendingInvite } from '../../utils/PendingInvite'
|
import { clearPendingInvite, setPendingInvite } from '../../utils/PendingInvite'
|
||||||
import AuthShell from '../Authorization/AuthShell'
|
|
||||||
import { authButtonSx } from '../Authorization/authStyles'
|
import { authButtonSx } from '../Authorization/authStyles'
|
||||||
import AcknowledgmentModal from '../Modals/Inputs/AcknowledgmentModal'
|
import AcknowledgmentModal from '../Modals/Inputs/AcknowledgmentModal'
|
||||||
|
import { CircleVignette } from '../Onboarding/OnboardingVignettes'
|
||||||
|
|
||||||
|
const EASE = 'cubic-bezier(0.22, 1, 0.36, 1)'
|
||||||
|
|
||||||
|
const enter = (delay = 0) => ({
|
||||||
|
animation: `joinCircleIn 520ms ${EASE} ${delay}ms both`,
|
||||||
|
'@keyframes joinCircleIn': {
|
||||||
|
from: { opacity: 0, transform: 'translateY(12px)' },
|
||||||
|
to: { opacity: 1, transform: 'none' },
|
||||||
|
},
|
||||||
|
'@media (prefers-reduced-motion: reduce)': { animation: 'none' },
|
||||||
|
})
|
||||||
|
|
||||||
const JoinCircleView = () => {
|
const JoinCircleView = () => {
|
||||||
const { data: userProfile, isLoading: isProfileLoading } = useUserProfile()
|
const { data: userProfile, isLoading: isProfileLoading } = useUserProfile()
|
||||||
@@ -38,8 +49,10 @@ const JoinCircleView = () => {
|
|||||||
clearPendingInvite()
|
clearPendingInvite()
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
showAcknowledgment(
|
showAcknowledgment(
|
||||||
'Your join request has been sent successfully! The circle admin will need to approve your request before you can access the circle and its chores. You will receive a notification once your request is approved.',
|
'Your request has been sent. A circle admin will need to approve ' +
|
||||||
'Join Request Sent!',
|
"it before you can access the circle and its chores. We'll " +
|
||||||
|
"notify you when it's approved.",
|
||||||
|
'Request sent',
|
||||||
() => navigate('/chores'),
|
() => navigate('/chores'),
|
||||||
'Got it',
|
'Got it',
|
||||||
'success',
|
'success',
|
||||||
@@ -57,7 +70,7 @@ const JoinCircleView = () => {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
setIsJoining(false)
|
setIsJoining(false)
|
||||||
clearPendingInvite()
|
clearPendingInvite()
|
||||||
showError('Failed to join circle, please try again')
|
showError('Could not send your join request. Please try again.')
|
||||||
})
|
})
|
||||||
}, [code, navigate, showAcknowledgment, showError])
|
}, [code, navigate, showAcknowledgment, showError])
|
||||||
|
|
||||||
@@ -89,14 +102,14 @@ const JoinCircleView = () => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
let title = "You've been invited to a circle"
|
let title = "You're invited to join a circle"
|
||||||
let subtitle = null
|
let subtitle = null
|
||||||
let body = null
|
let body = null
|
||||||
|
|
||||||
if (!code) {
|
if (!code) {
|
||||||
title = 'Invite link is incomplete'
|
title = 'Invite link is incomplete'
|
||||||
subtitle =
|
subtitle =
|
||||||
"This link doesn't include an invite code. Ask whoever invited you to send the link again."
|
'This invite link is missing a code. Ask the person who invited you to send a new link.'
|
||||||
body = (
|
body = (
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -111,7 +124,7 @@ const JoinCircleView = () => {
|
|||||||
// better to offer sign-in than to spin forever.
|
// better to offer sign-in than to spin forever.
|
||||||
} else if (!isAuthenticated || (!isProfileLoading && !userProfile)) {
|
} else if (!isAuthenticated || (!isProfileLoading && !userProfile)) {
|
||||||
subtitle =
|
subtitle =
|
||||||
'You need a Donetick account to join. Sign in or create one — we’ll send your join request as soon as you’re in.'
|
"Sign in or create a Donetick account to continue. We'll send your join request once you're signed in."
|
||||||
body = (
|
body = (
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
||||||
{inviteCodeField}
|
{inviteCodeField}
|
||||||
@@ -136,7 +149,7 @@ const JoinCircleView = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
} else if (isProfileLoading || isJoining) {
|
} else if (isProfileLoading || isJoining) {
|
||||||
title = 'Joining circle'
|
title = 'Sending your request'
|
||||||
subtitle = 'Sending your request…'
|
subtitle = 'Sending your request…'
|
||||||
body = (
|
body = (
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
|
||||||
@@ -144,19 +157,19 @@ const JoinCircleView = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
subtitle = `Hi ${
|
subtitle =
|
||||||
userProfile?.displayName || userProfile?.username
|
`Hi ${userProfile?.displayName || userProfile?.username}. ` +
|
||||||
}, joining gives you access to this circle's tasks and members.`
|
"Send a request to share this circle's chores with its members."
|
||||||
body = (
|
body = (
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
||||||
<Typography
|
<Typography
|
||||||
level='body-sm'
|
level='body-sm'
|
||||||
sx={{ textAlign: 'center', color: 'text.secondary' }}
|
sx={{ textAlign: 'center', color: 'text.secondary' }}
|
||||||
>
|
>
|
||||||
A circle admin approves your request before you get access.
|
A circle admin will review your request before you get access.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button fullWidth size='lg' sx={authButtonSx} onClick={submitJoin}>
|
<Button fullWidth size='lg' sx={authButtonSx} onClick={submitJoin}>
|
||||||
Join circle
|
Send join request
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -176,10 +189,72 @@ const JoinCircleView = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthShell title={title} subtitle={subtitle} showLogo>
|
<Box
|
||||||
{body}
|
component='main'
|
||||||
|
sx={{
|
||||||
|
minHeight: 'calc(100dvh - var(--safe-area-inset-top, 0px))',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
px: 3,
|
||||||
|
pb: 'calc(var(--safe-area-inset-bottom, 0px) + 24px)',
|
||||||
|
bgcolor: 'background.body',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 420,
|
||||||
|
my: 'auto',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ mb: 2, ...enter(0) }}>
|
||||||
|
<CircleVignette />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
gap: 1.5,
|
||||||
|
mb: 4,
|
||||||
|
...enter(60),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
level='h1'
|
||||||
|
sx={{
|
||||||
|
fontSize: '2rem',
|
||||||
|
fontWeight: 700,
|
||||||
|
letterSpacing: '-0.02em',
|
||||||
|
textWrap: 'balance',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
{subtitle && (
|
||||||
|
<Typography
|
||||||
|
level='body-md'
|
||||||
|
sx={{
|
||||||
|
color: 'text.secondary',
|
||||||
|
maxWidth: '34ch',
|
||||||
|
textWrap: 'pretty',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{subtitle}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box sx={{ ...enter(120) }}>{body}</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<AcknowledgmentModal config={ackModalConfig} />
|
<AcknowledgmentModal config={ackModalConfig} />
|
||||||
</AuthShell>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user