diff --git a/src/Providers.tsx b/src/Providers.tsx
index 5fb64144e..e2376fa8b 100644
--- a/src/Providers.tsx
+++ b/src/Providers.tsx
@@ -14,6 +14,7 @@ import { translations } from './i18n/components'
import { datesLocale } from './i18n/locales'
import { RoutesProvider } from './router/Router'
import { RainbowKitTheme, Theme } from './Theme'
+import { SaasAccountProvider } from '~components/AccountSaas/SaasAccountContext'
const queryClient = new QueryClient()
@@ -29,6 +30,17 @@ export const Providers = () => {
)
}
+const SaasProviders = ({ children }: PropsWithChildren<{}>) => {
+ if (!import.meta.env.SAAS_URL) {
+ return children
+ }
+ return (
+
+ {children}
+
+ )
+}
+
export const AppProviders = () => {
const { data } = useWalletClient()
const { address } = useAccount()
@@ -48,10 +60,10 @@ export const AppProviders = () => {
datesLocale={datesLocale(i18n.language)}
options={{ faucet_url: import.meta.env.CUSTOM_FAUCET_URL }}
>
-
+
-
+
)
diff --git a/src/components/AccountSaas/AccountTypes.ts b/src/components/AccountSaas/AccountTypes.ts
index 187dd85ff..0e22713f2 100644
--- a/src/components/AccountSaas/AccountTypes.ts
+++ b/src/components/AccountSaas/AccountTypes.ts
@@ -1,20 +1,24 @@
-export interface OrgInterface {
+import { AccountData, IAccount } from '@vocdoni/sdk'
+
+export type SaasOrganizationData = {
active: boolean
address: string
createdAt: string
- name: string
website: string
- description: string
size: string
type: string
country: string
timezone: string
language: string
- logo: string
header: string
subdomain: string
color: string
communications: boolean
}
-export type CreateOrgParams = Partial>
+export type OrganizationData = SaasOrganizationData & AccountData
+
+export type CreateOrgParams = Partial<
+ Pick &
+ Omit
+>
diff --git a/src/components/AccountSaas/Create.tsx b/src/components/AccountSaas/Create.tsx
index c0f9dd880..f9de2bf3b 100644
--- a/src/components/AccountSaas/Create.tsx
+++ b/src/components/AccountSaas/Create.tsx
@@ -65,8 +65,8 @@ export const AccountCreate = ({ children, ...props }: FlexProps) => {
.then(() => signer.getAddress()) // Get the address of newly created signer
.then(() =>
createAccount({
- name: values.name,
- description: values.description,
+ name: typeof values.name === 'object' ? values.name.default : values.name,
+ description: typeof values.description === 'object' ? values.description.default : values.description,
})
) // Create the new account on the vochain
.finally(() => setIsPending(false))
diff --git a/src/components/AccountSaas/EditProfile.tsx b/src/components/AccountSaas/EditProfile.tsx
index b15d51ea8..678380edd 100644
--- a/src/components/AccountSaas/EditProfile.tsx
+++ b/src/components/AccountSaas/EditProfile.tsx
@@ -15,40 +15,68 @@ import {
import { REGEX_AVATAR } from '~constants'
import useDarkMode from '~src/themes/saas/hooks/useDarkMode'
import fallback from '/assets/default-avatar.png'
-import { useEditSaasOrganization, useSaasOrganization } from '~components/AccountSaas/queries'
import FormSubmitMessage from '~components/Layout/FormSubmitMessage'
+import { useMutation, UseMutationOptions } from '@tanstack/react-query'
+import { useAuth } from '~components/Auth/useAuth'
+import { ApiEndpoints } from '~components/Auth/api'
+import { useSaasAccount } from '~components/AccountSaas/useSaasAccount'
+import { useClient } from '@vocdoni/react-providers'
+import { Account } from '@vocdoni/sdk'
type FormData = CustomOrgFormData & PrivateOrgFormData & CreateOrgParams
+const useEditSaasOrganization = (options?: Omit, 'mutationFn'>) => {
+ const { bearedFetch, signerAddress } = useAuth()
+ return useMutation({
+ mutationFn: (params: CreateOrgParams) =>
+ bearedFetch(ApiEndpoints.ORGANIZATION.replace('{address}', signerAddress), {
+ body: params,
+ method: 'PUT',
+ }),
+ ...options,
+ })
+}
+
const EditProfile = () => {
const { t } = useTranslation()
+ const {
+ updateAccount,
+ loading: { update: isUpdateLoading },
+ errors: { update: updateError },
+ } = useClient()
+ const { organization } = useSaasAccount()
- const { data } = useSaasOrganization()
- const { mutate, isPending, isError, error, isSuccess } = useEditSaasOrganization()
+ const {
+ mutateAsync,
+ isPending: isSaasPending,
+ isError: isSaasError,
+ error: saasError,
+ isSuccess,
+ } = useEditSaasOrganization()
const methods = useForm({
defaultValues: {
- name: data?.name || '',
- website: data?.website || '',
- description: data?.description || '',
- sizeSelect: data?.size && {
- value: data.size,
+ name: organization?.account.name.default || '',
+ website: organization?.website || '',
+ description: organization?.account.description.default || '',
+ sizeSelect: organization?.size && {
+ value: organization.size,
},
- typeSelect: data?.type && {
- value: data.type,
+ typeSelect: organization?.type && {
+ value: organization.type,
},
- countrySelect: data?.country && {
- value: data.country || '',
+ countrySelect: organization?.country && {
+ value: organization.country || '',
},
- communications: data?.communications || false,
- timeZoneSelect: data?.timezone && {
- value: data.timezone,
+ communications: organization?.communications || false,
+ timeZoneSelect: organization?.timezone && {
+ value: organization.timezone,
},
- languageSelect: data?.language && {
- value: data.language,
+ languageSelect: organization?.language && {
+ value: organization.language,
},
- logo: data?.logo || '',
- header: data?.header || '',
+ logo: organization?.account.avatar || '',
+ header: organization?.header || '',
},
})
@@ -56,23 +84,26 @@ const EditProfile = () => {
const onSubmit: SubmitHandler = async (values: FormData) => {
const newInfo: CreateOrgParams = {
- name: values.name,
website: values.website,
- description: values.description,
size: values.sizeSelect?.value,
type: values.typeSelect?.value,
country: values.countrySelect?.value,
timezone: values.timeZoneSelect.value,
language: values.languageSelect.value,
- logo: values.logo,
- header: values.header,
}
- mutate({
- ...data,
- ...newInfo,
- })
+
+ await mutateAsync({ ...organization, ...newInfo })
+ const newAccount = new Account({ ...organization?.account, ...values })
+ // Check if account changed before trying to update
+ if (JSON.stringify(newAccount.generateMetadata()) !== JSON.stringify(organization?.account.generateMetadata())) {
+ updateAccount(newAccount)
+ }
}
+ const isPending = isUpdateLoading || isSaasPending
+ const isError = isSaasError || !!updateError
+ const error = saasError || updateError
+
return (
@@ -106,6 +137,7 @@ const EditProfile = () => {
})}
| undefined>(undefined)
+
+export const SaasAccountProvider = ({ children }: { children: ReactNode }) => {
+ const isSaas = !!import.meta.env.SAAS_URL
+ const saasAcount = useSaasAccountProvider({ options: { enabled: isSaas } })
+ if (!isSaas) {
+ return children
+ }
+ return {children}
+}
diff --git a/src/components/AccountSaas/queries.ts b/src/components/AccountSaas/queries.ts
deleted file mode 100644
index fe0acce26..000000000
--- a/src/components/AccountSaas/queries.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { useMutation, UseMutationOptions, useQuery, UseQueryOptions } from '@tanstack/react-query'
-import { useAuth } from '~components/Auth/useAuth'
-import { ApiEndpoints } from '~components/Auth/api'
-import { CreateOrgParams, OrgInterface } from '~components/AccountSaas/AccountTypes'
-
-export const useEditSaasOrganization = (
- options?: Omit, 'mutationFn'>
-) => {
- const { bearedFetch, signerAddress } = useAuth()
- return useMutation({
- mutationFn: (params: CreateOrgParams) =>
- bearedFetch(ApiEndpoints.ORGANIZATION.replace('{address}', signerAddress), {
- body: params,
- method: 'PUT',
- }),
- ...options,
- })
-}
-
-export const useSaasOrganization = ({
- options,
-}: {
- options?: Omit, 'queryKey' | 'queryFn'>
-} = {}) => {
- const { bearedFetch, signerAddress } = useAuth()
-
- return useQuery({
- queryKey: ['organizations', 'info', signerAddress],
- queryFn: () => bearedFetch(ApiEndpoints.ORGANIZATION.replace('{address}', signerAddress)),
- enabled: !!signerAddress,
- ...options,
- })
-}
diff --git a/src/components/AccountSaas/useSaasAccount.ts b/src/components/AccountSaas/useSaasAccount.ts
new file mode 100644
index 000000000..7f5bd2551
--- /dev/null
+++ b/src/components/AccountSaas/useSaasAccount.ts
@@ -0,0 +1,10 @@
+import { useContext } from 'react'
+import { SaasAccountContext } from '~components/AccountSaas/SaasAccountContext'
+
+export const useSaasAccount = () => {
+ const context = useContext(SaasAccountContext)
+ if (!context) {
+ throw new Error('useSaasAccount must be used within an SaasAccountProvider')
+ }
+ return context
+}
diff --git a/src/components/AccountSaas/useSaasAccountProvider.ts b/src/components/AccountSaas/useSaasAccountProvider.ts
new file mode 100644
index 000000000..e44778f12
--- /dev/null
+++ b/src/components/AccountSaas/useSaasAccountProvider.ts
@@ -0,0 +1,50 @@
+import { useClient } from '@vocdoni/react-providers'
+import { useQuery, UseQueryOptions } from '@tanstack/react-query'
+import { OrganizationData } from '~components/AccountSaas/AccountTypes'
+import { useAuth } from '~components/Auth/useAuth'
+import { ApiEndpoints } from '~components/Auth/api'
+import { useCallback } from 'react'
+
+const useSaasOrganization = ({
+ options,
+}: {
+ options?: Omit, 'queryKey' | 'queryFn'>
+} = {}) => {
+ const { bearedFetch, signerAddress } = useAuth()
+
+ return useQuery({
+ queryKey: ['organizations', 'info', signerAddress],
+ queryFn: () => bearedFetch(ApiEndpoints.ORGANIZATION.replace('{address}', signerAddress)),
+ enabled: !!signerAddress,
+ ...options,
+ })
+}
+
+export const useSaasAccountProvider = (options?: Parameters[0]) => {
+ const {
+ account: accountSDK,
+ fetchAccount,
+ errors: { fetch: sdkAccountError },
+ loading: { fetch: sdkAccountLoading },
+ } = useClient()
+ const {
+ data: saasData,
+ refetch,
+ isLoading: isSaasLoading,
+ isError: isSaasError,
+ error: saasError,
+ } = useSaasOrganization(options)
+
+ const refetchAccount = useCallback(() => {
+ refetch()
+ fetchAccount()
+ }, [refetch, fetchAccount])
+
+ const organization: OrganizationData = { ...accountSDK, ...saasData }
+
+ const isLoading = isSaasLoading || sdkAccountLoading
+ const isError = isSaasError || !!sdkAccountError
+ const error = saasError || sdkAccountError
+
+ return { organization, refetchAccount, isLoading, isError, error }
+}
diff --git a/src/components/Layout/ErrorComponent.tsx b/src/components/Layout/ErrorComponent.tsx
index 48bda49bf..c11006df2 100644
--- a/src/components/Layout/ErrorComponent.tsx
+++ b/src/components/Layout/ErrorComponent.tsx
@@ -2,7 +2,7 @@ import { Flex, FlexProps, Text } from '@chakra-ui/react'
import { WarningIcon } from '@chakra-ui/icons'
import { useTranslation } from 'react-i18next'
-const ErrorComponent = ({ error, ...props }: { error: Error } & FlexProps) => {
+const ErrorComponent = ({ error, ...props }: { error: Error | string } & FlexProps) => {
const { t } = useTranslation()
return (
diff --git a/src/components/Layout/FormSubmitMessage.tsx b/src/components/Layout/FormSubmitMessage.tsx
index 015e5f04b..302d968c8 100644
--- a/src/components/Layout/FormSubmitMessage.tsx
+++ b/src/components/Layout/FormSubmitMessage.tsx
@@ -1,17 +1,22 @@
import { Box, BoxProps, FormControl, FormErrorMessage } from '@chakra-ui/react'
const FormSubmitMessage = ({
+ isLoading,
error,
isError,
isSuccess,
success,
...boxProps
}: {
+ isLoading?: boolean
error?: Error | string
isError?: boolean
isSuccess?: boolean
success?: string
} & BoxProps) => {
+ if (isLoading) {
+ return null
+ }
if (isSuccess) {
return (
diff --git a/src/components/Layout/QueryDataLayout.tsx b/src/components/Layout/QueryDataLayout.tsx
index da5eab6ed..73116fd5c 100644
--- a/src/components/Layout/QueryDataLayout.tsx
+++ b/src/components/Layout/QueryDataLayout.tsx
@@ -6,7 +6,7 @@ interface IUserQueryLayout {
isLoading: boolean
isEmpty?: boolean
isError: boolean
- error?: Error
+ error?: Error | string
}
const QueryDataLayout = ({ isLoading, isEmpty, isError, error, children }: IUserQueryLayout & PropsWithChildren) => {
diff --git a/src/elements/OrganizationSaas/Edit.tsx b/src/elements/OrganizationSaas/Edit.tsx
index 518ddf271..73c5dac56 100644
--- a/src/elements/OrganizationSaas/Edit.tsx
+++ b/src/elements/OrganizationSaas/Edit.tsx
@@ -1,9 +1,9 @@
import EditProfile from '~components/AccountSaas/EditProfile'
-import { useSaasOrganization } from '~components/AccountSaas/queries'
import QueryDataLayout from '~components/Layout/QueryDataLayout'
+import { useSaasAccount } from '~components/AccountSaas/useSaasAccount'
const OrganizationEdit = () => {
- const { isLoading, isError, error } = useSaasOrganization()
+ const { isLoading, isError, error } = useSaasAccount()
return (