Skip to content

Commit

Permalink
feat: new profilcard (#882)
Browse files Browse the repository at this point in the history
  • Loading branch information
OverGlass authored Oct 9, 2024
1 parent bd47b65 commit ae74ee6
Show file tree
Hide file tree
Showing 16 changed files with 251 additions and 67 deletions.
2 changes: 1 addition & 1 deletion app/(app)/(tabs)/(home)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const HomeScreen: React.FC = () => {
<PageLayout.MainSingleColumn>
<BoundarySuspenseWrapper
fallback={
<YStack gap="$4" padding="$8" $sm={{ paddingHorizontal: 0, paddingTop: '$4' }}>
<YStack gap="$4" padding="$5" $sm={{ paddingHorizontal: 0, paddingTop: '$4' }}>
<SkeCard>
<SkeCard.Content>
<SkeCard.Chip />
Expand Down
19 changes: 11 additions & 8 deletions app/(app)/(tabs)/evenements/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ProfileLoginCTA from '@/components/ProfileCards/ProfileLoginCTA/ProfileLo
import AuthFallbackWrapper from '@/components/Skeleton/AuthFallbackWrapper'
import SkeCard from '@/components/Skeleton/CardSkeleton'
import { Tabs } from '@/components/Tabs/Tabs'
import VoxCard from '@/components/VoxCard/VoxCard'
import * as metatags from '@/config/metatags'
import { useSession } from '@/ctx/SessionProvider'
import Head from 'expo-router/head'
Expand All @@ -31,10 +32,6 @@ const EventsScreen: React.FC = () => {
<YStack gap="$3">
<AuthFallbackWrapper fallback={<ProfileLoginCTA />} />
<MyProfileCard />
<ProcurationCTA />
<AuthFallbackWrapper>
<AppDownloadCTA />
</AuthFallbackWrapper>
</YStack>
</PageLayout.SideBarLeft>
<PageLayout.MainSingleColumn>
Expand All @@ -43,16 +40,16 @@ const EventsScreen: React.FC = () => {
<Tabs<'events' | 'myEvents'>
value={activeTab}
onChange={setActiveTab}
grouped={media.lg}
$gtMd={{ paddingHorizontal: '$7', paddingTop: '$6', paddingBottom: 0 }}
grouped={media.gtMd}
$gtMd={{ paddingHorizontal: '$5', paddingTop: '$4', paddingBottom: 0 }}
>
<Tabs.Tab id="events">Tous les événements</Tabs.Tab>
<Tabs.Tab id="myEvents">J'y participe</Tabs.Tab>
</Tabs>
)}
<BoundarySuspenseWrapper
fallback={
<YStack gap="$4" padding="$8" $sm={{ paddingHorizontal: 0, paddingTop: '$4' }}>
<YStack gap="$4" padding="$5" $sm={{ paddingHorizontal: 0, paddingTop: '$4' }}>
<SkeCard>
<SkeCard.Content>
<SkeCard.Chip />
Expand Down Expand Up @@ -102,7 +99,13 @@ const EventsScreen: React.FC = () => {
</BoundarySuspenseWrapper>
</PageLayout.MainSingleColumn>
<PageLayout.SideBarRight>
<EventFilterForm />
<VoxCard.Content>
<EventFilterForm />
<ProcurationCTA />
<AuthFallbackWrapper>
<AppDownloadCTA />
</AuthFallbackWrapper>
</VoxCard.Content>
</PageLayout.SideBarRight>
</PageLayout>
</>
Expand Down
3 changes: 1 addition & 2 deletions app/(app)/(tabs)/ressources/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const DoubleRessourceCardSkeleton = () => {

const ToolsSkeleton = () => {
return (
<YStack gap="$4" padding="$8" $sm={{ paddingTop: '$4' }}>
<YStack gap="$4" padding="$5" $sm={{ paddingTop: '$4' }}>
<DoubleRessourceCardSkeleton />
<DoubleRessourceCardSkeleton />
<DoubleRessourceCardSkeleton />
Expand All @@ -50,7 +50,6 @@ const ToolsScreen: React.FC = () => {
<PageLayout.SideBarLeft>
<View gap={'$2'}>
<MyProfileCard />
<AppDownloadCTA />
</View>
</PageLayout.SideBarLeft>
<PageLayout.MainSingleColumn>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface ProfileCallToActionProps extends PropsWithChildren {

function Layout({ children, backgroundColor, height, noPadding = false, noBorder = false }: Readonly<ProfileCallToActionProps>) {
return (
<VoxCard padding={noPadding ? undefined : '$4'} backgroundColor={backgroundColor ?? '$white1'} height={height} inside overflow={'hidden'}>
<VoxCard padding={noPadding ? undefined : '$4'} backgroundColor={backgroundColor ?? '$white1'} height={height} overflow={'hidden'}>
{children && <SpacedContainer>{children}</SpacedContainer>}
</VoxCard>
)
Expand Down
180 changes: 165 additions & 15 deletions src/components/ProfileCards/ProfileCard/MyProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,144 @@
import { useCallback } from 'react'
import ProfileCard from '@/components/ProfileCards/ProfileCard/ProfileCard'
import { NamedExoticComponent, useCallback } from 'react'
import Text from '@/components/base/Text'
import BoundarySuspenseWrapper from '@/components/BoundarySuspenseWrapper'
import { VoxButton } from '@/components/Button'
import Menu from '@/components/menu/Menu'
import VoxCard from '@/components/VoxCard/VoxCard'
import clientEnv from '@/config/clientEnv'
import { useSession } from '@/ctx/SessionProvider'
import { useGetProfil } from '@/services/profile/hook'
import ProfilBlock from '@/screens/profil/dashboard/components/ProfilBlock'
import { useGetProfil, useGetUserScopes } from '@/services/profile/hook'
import { RestProfilResponse } from '@/services/profile/schema'
import { useUserStore } from '@/store/user-store'
import { ErrorMonitor } from '@/utils/ErrorMonitor'
import type { IconProps } from '@tamagui/helpers-icon'
import { ChevronRight, ClipboardCheck, GraduationCap, History, Link as LinkIcon, SquareUser, UserPlus } from '@tamagui/lucide-icons'
import { getYear } from 'date-fns'
import { openURL } from 'expo-linking'
import { Href, Link } from 'expo-router'
import { isWeb, ThemeName, XStack, YStack } from 'tamagui'

const GoToAdminCard = ({ profil }: { profil: RestProfilResponse }) => {
const { user: credentials } = useUserStore()
const scopes = useGetUserScopes({ enabled: !!credentials })
const isCadre = profil?.cadre_auth_path && scopes?.data && scopes.data.length > 0
const onNavigateToCadre = useCallback(() => {
if (isCadre) openURL(`${credentials?.isAdmin ? clientEnv.ADMIN_URL : clientEnv.OAUTH_BASE_URL}${profil?.cadre_auth_path}`)
}, [profil])
if (!isCadre) {
return null
}
return (
<VoxCard
inside={true}
bg="$purple1"
onPress={onNavigateToCadre}
cursor="pointer"
animation="100ms"
hoverStyle={{
bg: '$purple2',
}}
pressStyle={{
bg: '$purple3',
}}
>
<VoxCard.Content>
<XStack justifyContent="space-between" alignItems="center">
<YStack flexShrink={1} flex={1}>
<Text.MD color="$purple6" semibold>
{scopes.data[0].name}
</Text.MD>
{scopes.data[0].zones.map((z) => (
<Text.P color="$purple6">
{z.name} ({z.code})
</Text.P>
))}
</YStack>
<YStack>
<ChevronRight size="$1" color="$purple6" />
</YStack>
</XStack>
</VoxCard.Content>
</VoxCard>
)
}

const InfoCard = (props: {
buttonText: string
icon: NamedExoticComponent<IconProps>
children: string | string[]
href: Href<string | object>
theme?: ThemeName | null
}) => {
return (
<VoxCard inside bg="$color1" theme={props.theme}>
<VoxCard.Content justifyContent="space-between" alignItems="center">
<props.icon size={24} color="$color5" />
<YStack flexShrink={1}>
<Text.SM multiline textAlign="center" color="$color7">
{props.children}
</Text.SM>
</YStack>
<YStack width="100%">
<Link href={props.href} asChild={!isWeb}>
<VoxButton full inverse theme={props.theme}>
{props.buttonText}
</VoxButton>
</Link>
</YStack>
</VoxCard.Content>
</VoxCard>
)
}
export const getMembershipCardStatus = (tags: RestProfilResponse['tags']): 'renew' | 'tofinish' | null => {
const codes = tags.map((tag) => tag.code)

if (codes.includes('sympathisant:adhesion_incomplete')) {
return 'tofinish'
}
const AtDate = codes.find((code) => code.startsWith('adherent:a_jour_'))
if (AtDate) {
const todayYear = new Date().getFullYear()
const codeYear = parseInt(AtDate.split('_')[2])
if (!codeYear || Number.isNaN(codeYear)) {
ErrorMonitor.log(`Invalid tag code date parsing: ${AtDate}`)
return null
}
return codeYear >= todayYear ? null : 'renew'
}

return null
}

const MembershipCard = ({ status }: { status: 'renew' | 'tofinish' }) => {
const buttonText = status === 'renew' ? `Recotiser pour ${getYear(new Date())}` : 'Je finalise mon adhésion'
const text =
status === 'renew'
? `Mettez-vous à jour de cotisation dès maintenant pour garder vos avantages adhérents.`
: 'Finalisez votre adhésion dès maintenant pour profiter des avantages adhérent'
const icon = status === 'renew' ? History : UserPlus

return (
<InfoCard buttonText={buttonText} icon={icon} href="/profil/cotisation-et-dons" theme="yellow">
{text}
</InfoCard>
)
}

const EluCard = () => {
return (
<InfoCard buttonText="Je complète mon informations d’élu" icon={SquareUser} href="/profil/informations-elu" theme="green">
Complétez votre profil d’élu pour participer à l’Assemblée des territoires.
</InfoCard>
)
}

export default function MyProfileCard() {
const { session } = useSession()
const { user: credentials } = useUserStore()
const user = useGetProfil({ enabled: !!session })
const profile = user?.data
const onNavigateToCadre = useCallback(
() => openURL(`${credentials?.isAdmin ? clientEnv.ADMIN_URL : clientEnv.OAUTH_BASE_URL}${profile?.cadre_auth_path}`),
[profile],
)
const statusAdh = profile ? getMembershipCardStatus(profile.tags) : null
const showEluCard = (profile?.tags ?? []).map((tag) => tag.code).find((x) => ['elu:attente_declaration', 'elu:cotisation_nok'].includes(x))

if (!profile) {
return null
Expand All @@ -25,12 +149,38 @@ export default function MyProfileCard() {
}

return (
<ProfileCard
lastName={profile.last_name}
firstName={profile.first_name}
src={user.data?.image_url ?? undefined}
tags={profile.tags}
onButtonPress={profile.cadre_access ? onNavigateToCadre : undefined}
/>
<VoxCard bg="$white" overflow="hidden">
<YStack>
<VoxCard.Content>
<BoundarySuspenseWrapper>
<Link href="/profil" asChild={!isWeb}>
<ProfilBlock
editablePicture={false}
inside
bg="$textSurface"
animation="100ms"
hoverStyle={{
bg: '$gray1',
}}
/>
</Link>
</BoundarySuspenseWrapper>
{!showEluCard && statusAdh ? <MembershipCard status={statusAdh} /> : null}
{showEluCard ? <EluCard /> : null}
<GoToAdminCard profil={profile} />
</VoxCard.Content>
<Link href="/ressources" asChild={!isWeb}>
<Menu.Item size="sm" icon={LinkIcon} showArrow>
Ressources
</Menu.Item>
</Link>
<Menu.Item size="sm" icon={GraduationCap} showArrow disabled>
Formations (bientôt disponible)
</Menu.Item>
<Menu.Item size="sm" icon={ClipboardCheck} showArrow disabled>
Questionnaires (bientôt disponible)
</Menu.Item>
</YStack>
</VoxCard>
)
}
3 changes: 3 additions & 0 deletions src/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const StyledFrame = styled(XStack, {
grouped: {
true: {
bg: '$white1',
$gtMd: {
bg: '$colorTransparent',
},
gap: 0,
padding: 0,
},
Expand Down
8 changes: 5 additions & 3 deletions src/components/VoxCard/VoxCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import AutoSizeImage from '../AutoSizeImage'

const CardFrame = styled(YStack, {
backgroundColor: '$white1',

$gtSm: {
borderRadius: '$8',
borderRadius: 16,
},
variants: {
inside: {
true: {
borderRadius: '$6',
borderRadius: 8,
$gtSm: {
borderRadius: 8,
},
},
false: {
elevation: 1,
Expand Down
4 changes: 2 additions & 2 deletions src/components/events/EventFeedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ const EventList = ({ activeTab }: { activeTab: 'events' | 'myEvents' }) => {
// height: '100%',
gap: getToken('$4', 'space'),
paddingTop: 0,
paddingLeft: media.gtSm ? getToken('$7', 'space') : undefined,
paddingRight: media.gtSm ? getToken('$7', 'space') : undefined,
paddingLeft: media.gtSm ? getToken('$5', 'space') : undefined,
paddingRight: media.gtSm ? getToken('$5', 'space') : undefined,
paddingBottom: getToken('$10', 'space'),
// height: feedData.length === 0 && !isLoading && media.sm ? '100%' : undefined,
}}
Expand Down
2 changes: 1 addition & 1 deletion src/components/events/detail/EventComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { isPast } from 'date-fns'
import { ScrollView, ScrollViewProps, Sheet, useMedia, XStack } from 'tamagui'
import { useHandleCopyUrl } from './utils'

const padding = '$7'
const padding = '$5'

export function ScrollStack({ children }: ScrollViewProps) {
const media = useMedia()
Expand Down
2 changes: 1 addition & 1 deletion src/components/layouts/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ComponentProps } from 'react'
import Container from '@/components/layouts/Container'
import { Media, StackProps, useMedia, View, ViewProps, withStaticProperties, XStack, YStack, YStackProps } from 'tamagui'

export const padding = '$7'
export const padding = '$5'
export const columnWidth = 333

const LayoutFrame = ({ children, ...props }: ComponentProps<typeof Container>) => {
Expand Down
Loading

0 comments on commit ae74ee6

Please sign in to comment.