Skip to content

Commit

Permalink
refs #854 Merge remote-tracking branch 'origin/develop' into f/alerts…
Browse files Browse the repository at this point in the history
…-854
  • Loading branch information
elboletaire committed Dec 3, 2024
2 parents 0fc2917 + 4decc98 commit 6665b7e
Show file tree
Hide file tree
Showing 63 changed files with 1,996 additions and 931 deletions.
File renamed without changes.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@stripe/react-stripe-js": "^2.7.0",
"@stripe/stripe-js": "^3.3.0",
"@tanstack/react-query": "^5.59.15",
"@untitled-ui/icons-react": "^0.1.3",
"@vocdoni/chakra-components": "^0.9.6",
"@vocdoni/rainbowkit-wallets": "^0.2.2",
"@vocdoni/sdk": "~0.9.1",
Expand Down
5 changes: 4 additions & 1 deletion src/Providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next'
import { useAccount, useWalletClient, WagmiConfig } from 'wagmi'
import { SaasAccountProvider } from '~components/Account/SaasAccountContext'
import { AuthProvider } from '~components/Auth/AuthContext'
import { SubscriptionProvider } from '~components/Auth/Subscription'
import { walletClientToSigner } from '~constants/wagmi-adapters'
import { VocdoniEnvironment } from './constants'
import { chains, wagmiConfig } from './constants/rainbow'
Expand All @@ -32,7 +33,9 @@ export const Providers = () => {

const SaasProviders = ({ children }: PropsWithChildren<{}>) => (
<AuthProvider>
<SaasAccountProvider>{children}</SaasAccountProvider>
<SubscriptionProvider>
<SaasAccountProvider>{children}</SaasAccountProvider>
</SubscriptionProvider>
</AuthProvider>
)

Expand Down
74 changes: 0 additions & 74 deletions src/components/Account/useAccountPlan.tsx

This file was deleted.

67 changes: 67 additions & 0 deletions src/components/Auth/Subscription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { createContext } from '@chakra-ui/react-utils'
import { useQuery } from '@tanstack/react-query'
import { useClient } from '@vocdoni/react-providers'
import { dotobject, ensure0x } from '@vocdoni/sdk'
import { ReactNode, useMemo } from 'react'
import { useAuth } from '~components/Auth/useAuth'
import type { Plan } from '~components/Pricing/Plans'
import { ApiEndpoints } from './api'

type PermissionsContextType = {
permission: (key: string) => any
subscription: SubscriptionType
loading: boolean
}

type SubscriptionType = {
subscriptionDetails: {
planID: number
startDate: string // ISO 8601 Date String
endDate: string // ISO 8601 Date String
renewalDate: string // ISO 8601 Date String
active: boolean
maxCensusSize: number
}
usage: {
sentSMS: number
sentEmails: number
subOrgs: number
members: number
}
plan: Plan
}

const [SubscriptionProvider, useSubscription] = createContext<PermissionsContextType>({
name: 'PermissionsContext',
errorMessage: 'usePermissions must be used within a PermissionsProvider',
})

const SubscriptionProviderComponent: React.FC<{ children: ReactNode }> = ({ children }) => {
const { bearedFetch } = useAuth()
const { account } = useClient()

// Fetch organization subscription details
// TODO: In the future, this may be merged with the role permissions (not yet defined)
const { data: subscription, isFetching } = useQuery({
queryKey: ['organizationSubscription', account?.address],
queryFn: () =>
bearedFetch<SubscriptionType>(
ApiEndpoints.OrganizationSubscription.replace('{address}', ensure0x(account?.address))
),
// Cache for 15 minutes
staleTime: 15 * 60 * 1000,
enabled: !!account?.address,
})

// Helper function to access permission using dot notation
const permission = useMemo(() => {
return (key: string) => {
if (!subscription || !subscription.plan) return undefined
return dotobject(subscription.plan, key)
}
}, [subscription])

return <SubscriptionProvider value={{ permission, subscription, loading: isFetching }} children={children} />
}

export { SubscriptionProviderComponent as SubscriptionProvider, useSubscription }
4 changes: 3 additions & 1 deletion src/components/Auth/api.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
type MethodTypes = 'GET' | 'POST' | 'PUT' | 'DELETE'

export enum ApiEndpoints {
InviteAccept = 'organizations/{address}/members/accept',
Login = 'auth/login',
Me = 'users/me',
InviteAccept = 'organizations/{address}/members/accept',
Organization = 'organizations/{address}',
OrganizationMembers = 'organizations/{address}/members',
OrganizationPendingMembers = 'organizations/{address}/members/pending',
Organizations = 'organizations',
OrganizationsRoles = 'organizations/roles',
OrganizationSubscription = 'organizations/{address}/subscription',
Password = 'users/password',
PasswordRecovery = 'users/password/recovery',
PasswordReset = 'users/password/reset',
Plans = 'plans',
Refresh = 'auth/refresh',
Register = 'users',
Verify = 'users/verify',
Expand Down
9 changes: 3 additions & 6 deletions src/components/Dashboard/Menu/Options.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Box, Button, Collapse, useDisclosure } from '@chakra-ui/react'
import { Box, Collapse, useDisclosure } from '@chakra-ui/react'
import { OrganizationName } from '@vocdoni/chakra-components'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { HiSquares2X2 } from 'react-icons/hi2'
import { IoIosSettings } from 'react-icons/io'
import { generatePath, matchPath, useLocation } from 'react-router-dom'
import { Routes } from '~src/router/routes'
import { PricingModal } from '../PricingModal'
import { DashboardMenuItem } from './Item'

type MenuItem = {
Expand Down Expand Up @@ -53,9 +52,9 @@ export const DashboardMenuOptions = () => {
icon: IoIosSettings,
children: [
{ label: t('organization.organization'), route: Routes.dashboard.organization },
{ label: t('team'), route: Routes.dashboard.team },
{ label: t('team.title'), route: Routes.dashboard.team },
// { label: t('billing'), route: '#billing' },
// { label: t('subscription'), route: '#subscription' },
{ label: t('subscription'), route: Routes.dashboard.subscription },
{ label: t('profile'), route: Routes.dashboard.profile },
],
},
Expand Down Expand Up @@ -84,8 +83,6 @@ export const DashboardMenuOptions = () => {

return (
<Box>
<PricingModal isOpenModal={isOpen} onCloseModal={onClose} />
<Button onClick={onOpen}>Open Modal</Button>
<OrganizationName color='text.secondary' mb={2.5} />
{menuItems.map((item, index) => (
<Box key={index}>
Expand Down
126 changes: 0 additions & 126 deletions src/components/Dashboard/PricingModal.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/Dashboard/ProcessView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const ProcessView = () => {
{/* Features Section */}
<DashboardBox textAlign='center' display='flex' flexDir='column' gap={3}>
<Heading as='h4' variant='sidebar-section'>
<Trans i18nKey='features'>Features</Trans>
<Trans i18nKey='features.title'>Features</Trans>
</Heading>
<HStack spacing={3} justifyContent='center'>
<Text fontSize='sm'>Feature 1</Text>
Expand Down
28 changes: 28 additions & 0 deletions src/components/Layout/Form/DetailedCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Checkbox, CheckboxProps, Text, useMultiStyleConfig } from '@chakra-ui/react'
import { cloneElement, ReactElement } from 'react'
import { useFormContext } from 'react-hook-form'

export type DetailedCheckboxProps = CheckboxProps & {
badge?: ReactElement
description?: string
icon?: ReactElement
name: string
title: string
}

export const DetailedCheckbox = ({ icon, badge, title, description, name, ...props }: DetailedCheckboxProps) => {
const styles = useMultiStyleConfig('DetailedCheckbox', props)
const { register } = useFormContext()

return (
<Checkbox variant='detailed' {...register(name)} {...props} sx={styles.checkbox}>
<Text sx={styles.title}>
{icon && cloneElement(icon, { sx: styles.icon })}
{title}
</Text>
<Text sx={styles.description}>{description}</Text>

{badge && cloneElement(badge, { sx: styles.badge })}
</Checkbox>
)
}
Loading

0 comments on commit 6665b7e

Please sign in to comment.