From 9dacc9bf2fa38806bde715ba42fa6d8108599f33 Mon Sep 17 00:00:00 2001 From: selankon Date: Wed, 2 Oct 2024 09:58:12 +0200 Subject: [PATCH 01/12] Add missing account attributes --- src/components/AccountSaas/AccountTypes.ts | 6 +++++- src/components/AccountSaas/Create.tsx | 11 ++++++++--- src/components/AccountSaas/Layout.tsx | 1 - 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/AccountSaas/AccountTypes.ts b/src/components/AccountSaas/AccountTypes.ts index 58c83f79d..187dd85ff 100644 --- a/src/components/AccountSaas/AccountTypes.ts +++ b/src/components/AccountSaas/AccountTypes.ts @@ -1,4 +1,7 @@ export interface OrgInterface { + active: boolean + address: string + createdAt: string name: string website: string description: string @@ -11,6 +14,7 @@ export interface OrgInterface { header: string subdomain: string color: string + communications: boolean } -export type CreateOrgParams = Partial +export type CreateOrgParams = Partial> diff --git a/src/components/AccountSaas/Create.tsx b/src/components/AccountSaas/Create.tsx index cf925ef0a..7e946138b 100644 --- a/src/components/AccountSaas/Create.tsx +++ b/src/components/AccountSaas/Create.tsx @@ -8,13 +8,13 @@ import { useClient } from '@vocdoni/react-providers' import { useState } from 'react' import { useAccountCreate } from '~components/Account/useAccountCreate' import { CreateOrgParams, OrgInterface } from '~components/AccountSaas/AccountTypes' -import { PrivateOrgFormData, PrivateOrgForm, PublicOrgForm } from '~components/AccountSaas/Layout' +import { PrivateOrgForm, PrivateOrgFormData, PublicOrgForm } from '~components/AccountSaas/Layout' import { ApiEndpoints } from '~components/Auth/api' import { useAuth } from '~components/Auth/useAuth' import useDarkMode from '~src/themes/saas/hooks/useDarkMode' import LogoutBtn from '~components/AccountSaas/LogoutBtn' -type FormData = PrivateOrgFormData & Pick +type FormData = PrivateOrgFormData & Pick // This specific error message should be ignored and not displayed in the UI. // Context: After login, a RemoteSigner is created and passed to the SDK via the useClient hook. @@ -64,7 +64,12 @@ export const AccountCreate = ({ children, ...props }: FlexProps) => { type: values.typeSelect?.value, }) .then(() => signer.getAddress()) // Get the address of newly created signer - .then(() => createAccount({ name: values.name, description: values.description })) // Create the new account on the vochain + .then(() => + createAccount({ + name: values.name, + description: values.description, + }) + ) // Create the new account on the vochain .finally(() => setIsPending(false)) } diff --git a/src/components/AccountSaas/Layout.tsx b/src/components/AccountSaas/Layout.tsx index 72e951487..11bf0c327 100644 --- a/src/components/AccountSaas/Layout.tsx +++ b/src/components/AccountSaas/Layout.tsx @@ -56,7 +56,6 @@ export const PublicOrgForm = () => { } export type PrivateOrgFormData = { - communications: boolean sizeSelect: SelectOptionType typeSelect: SelectOptionType countrySelect: SelectOptionType From 57a4b9bc120fb1027a1671bd81a22eb5414803d2 Mon Sep 17 00:00:00 2001 From: selankon Date: Wed, 2 Oct 2024 10:08:33 +0200 Subject: [PATCH 02/12] Implement QueryDataLayout --- src/components/Layout/QueryDataLayout.tsx | 25 ++++ .../OrganizationSaas/Dashboard/Team.tsx | 115 ++++++++---------- 2 files changed, 77 insertions(+), 63 deletions(-) create mode 100644 src/components/Layout/QueryDataLayout.tsx diff --git a/src/components/Layout/QueryDataLayout.tsx b/src/components/Layout/QueryDataLayout.tsx new file mode 100644 index 000000000..da5eab6ed --- /dev/null +++ b/src/components/Layout/QueryDataLayout.tsx @@ -0,0 +1,25 @@ +import ErrorComponent from '~components/Layout/ErrorComponent' +import { PropsWithChildren } from 'react' +import { Loading } from '~src/router/SuspenseLoader' + +interface IUserQueryLayout { + isLoading: boolean + isEmpty?: boolean + isError: boolean + error?: Error +} + +const QueryDataLayout = ({ isLoading, isEmpty, isError, error, children }: IUserQueryLayout & PropsWithChildren) => { + if (isLoading) { + return + } + if (isError) { + return + } + if (isEmpty) { + return null + } + return <>{children} +} + +export default QueryDataLayout diff --git a/src/components/OrganizationSaas/Dashboard/Team.tsx b/src/components/OrganizationSaas/Dashboard/Team.tsx index ad8dd2f29..2c0b23d34 100644 --- a/src/components/OrganizationSaas/Dashboard/Team.tsx +++ b/src/components/OrganizationSaas/Dashboard/Team.tsx @@ -4,7 +4,6 @@ import { Box, Button, Flex, - Heading, Table, TableContainer, Tbody, @@ -19,9 +18,8 @@ import Invite from './Invite' import { useAuth } from '~components/Auth/useAuth' import { useQuery, UseQueryOptions } from '@tanstack/react-query' import { ApiEndpoints } from '~components/Auth/api' -import { Loading } from '~src/router/SuspenseLoader' -import ErrorComponent from '~components/Layout/ErrorComponent' -import { Trans, useTranslation } from 'react-i18next' +import { Trans } from 'react-i18next' +import QueryDataLayout from '~components/Layout/QueryDataLayout' type UserInfo = { email: string @@ -50,70 +48,61 @@ const useTeamMembers = ({ } const TeamList = () => { - const { t } = useTranslation() const { data, isLoading, isError, error } = useTeamMembers() - if (isLoading) { - return - } - if (isError) { - return - } - if (!data.members) { - return null - } - const members = data.members return ( - - - Team members - - {members.length} - - - - - - - - - - - - {members.map((member, i) => { - return ( - - - - - ) - })} - -
- Name - - Permission -
- - - - - {member.info.firstName} {member.info.lastName} - - {member.info.email} - - - - {member.role} -
-
-
+ + + + Team members + + {members.length} + + + + + + + + + + + + {members.map((member, i) => { + return ( + + + + + ) + })} + +
+ Name + + Permission +
+ + + + + {member.info.firstName} {member.info.lastName} + + {member.info.email} + + + + {member.role} +
+
+
+
) } From 0256cdb9d1d32254ba607f9c97144794aacefe44 Mon Sep 17 00:00:00 2001 From: selankon Date: Wed, 2 Oct 2024 10:09:55 +0200 Subject: [PATCH 03/12] Implement useSaasOrganization --- src/components/Account/useAccountCreate.tsx | 1 - src/components/AccountSaas/EditProfile.tsx | 38 ++++++++++++++------- src/components/AccountSaas/queries.ts | 35 +++++++++++++++++++ src/components/Auth/api.ts | 1 + src/elements/OrganizationSaas/Edit.tsx | 12 ++++++- 5 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 src/components/AccountSaas/queries.ts diff --git a/src/components/Account/useAccountCreate.tsx b/src/components/Account/useAccountCreate.tsx index 6da08feea..65844cbea 100644 --- a/src/components/Account/useAccountCreate.tsx +++ b/src/components/Account/useAccountCreate.tsx @@ -1,5 +1,4 @@ import { useClient } from '@vocdoni/react-providers' -import { useMutation, UseMutationOptions, useQuery } from '@tanstack/react-query' import { Account } from '@vocdoni/sdk' import { useAccountHealthTools } from '~components/Account/use-account-health-tools' diff --git a/src/components/AccountSaas/EditProfile.tsx b/src/components/AccountSaas/EditProfile.tsx index bf2438b9d..a4003e5af 100644 --- a/src/components/AccountSaas/EditProfile.tsx +++ b/src/components/AccountSaas/EditProfile.tsx @@ -1,6 +1,5 @@ import { AspectRatio, Box, Flex, FormControl, FormLabel, IconButton, Image, Input, Text } from '@chakra-ui/react' import { Button } from '@vocdoni/chakra-components' -import { useClient } from '@vocdoni/react-providers' import { FormProvider, SubmitHandler, useForm } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { BiTrash } from 'react-icons/bi' @@ -16,27 +15,40 @@ import { import { REGEX_AVATAR } from '~constants' import useDarkMode from '~src/themes/saas/hooks/useDarkMode' import fallback from '/assets/default-avatar.png' +import { useSaasOrganization } from '~components/AccountSaas/queries' type FormData = CustomOrgFormData & PrivateOrgFormData & - Pick + Pick const EditProfile = () => { - const { account } = useClient() + const { data } = useSaasOrganization() + const { t } = useTranslation() const methods = useForm({ defaultValues: { - name: account?.account.name.default || '', - // website: account?.account. || '', - description: account?.account.description.default || '', - // size: account?.account.name.default || '', - // type: account?.account.name.default || '', - // country: account?.account.name.default || '', - // timezone: account?.account.name.default || '', - // language: account?.account.name.default || '', - logo: account?.account.avatar || '', - header: account?.account.header || '', + name: data?.name || '', + website: data?.website || '', + description: data?.description || '', + sizeSelect: data?.size && { + value: data.size, + }, + typeSelect: data?.type && { + value: data.type, + }, + countrySelect: data?.country && { + value: data.country || '', + }, + communications: data?.communications || false, + timeZoneSelect: data?.timezone && { + value: data.timezone, + }, + languageSelect: data?.language && { + value: data.language, + }, + logo: data?.logo || '', + header: data?.header || '', }, }) diff --git a/src/components/AccountSaas/queries.ts b/src/components/AccountSaas/queries.ts new file mode 100644 index 000000000..475646da1 --- /dev/null +++ b/src/components/AccountSaas/queries.ts @@ -0,0 +1,35 @@ +import { useQuery, UseQueryOptions } from '@tanstack/react-query' +import { useAuth } from '~components/Auth/useAuth' +import { ApiEndpoints } from '~components/Auth/api' +import { OrgInterface } from '~components/AccountSaas/AccountTypes' + +export const useEditSaasOrganization = ({ + options, +}: { + options?: Omit, 'queryKey' | 'queryFn'> +} = {}) => { + // todo(kon) + // const { bearedFetch, signerAddress } = useAuth() + // + // return useQuery({ + // queryKey: ['organizations', 'info', signerAddress], + // queryFn: () => bearedFetch(ApiEndpoints.ORGANIZATION_INFO.replace('{address}', signerAddress)), + // enabled: !!signerAddress, + // ...options, + // }) +} + +export const useSaasOrganization = ({ + options, +}: { + options?: Omit, 'queryKey' | 'queryFn'> +} = {}) => { + const { bearedFetch, signerAddress } = useAuth() + + return useQuery({ + queryKey: ['organizations', 'info', signerAddress], + queryFn: () => bearedFetch(ApiEndpoints.ORGANIZATION_INFO.replace('{address}', signerAddress)), + enabled: !!signerAddress, + ...options, + }) +} diff --git a/src/components/Auth/api.ts b/src/components/Auth/api.ts index 8637abae4..87c597adf 100644 --- a/src/components/Auth/api.ts +++ b/src/components/Auth/api.ts @@ -7,6 +7,7 @@ export enum ApiEndpoints { VERIFY = 'users/verify', RESEND_VERIFICATION = 'users/verify/code', ACCOUNT_CREATE = 'organizations', + ORGANIZATION_INFO = 'organizations/{address}', TEAM_MEMBERS = 'organizations/{address}/members', } diff --git a/src/elements/OrganizationSaas/Edit.tsx b/src/elements/OrganizationSaas/Edit.tsx index fbb9cad3d..518ddf271 100644 --- a/src/elements/OrganizationSaas/Edit.tsx +++ b/src/elements/OrganizationSaas/Edit.tsx @@ -1,5 +1,15 @@ import EditProfile from '~components/AccountSaas/EditProfile' +import { useSaasOrganization } from '~components/AccountSaas/queries' +import QueryDataLayout from '~components/Layout/QueryDataLayout' -const OrganizationEdit = () => +const OrganizationEdit = () => { + const { isLoading, isError, error } = useSaasOrganization() + + return ( + + + + ) +} export default OrganizationEdit From e0ceebc59218d9c963af639524ff5bb5b2e14ca2 Mon Sep 17 00:00:00 2001 From: selankon Date: Wed, 2 Oct 2024 10:10:13 +0200 Subject: [PATCH 04/12] Fix SaaS selector to show label --- src/components/Layout/SaasSelector.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Layout/SaasSelector.tsx b/src/components/Layout/SaasSelector.tsx index 8a2b9a312..b9609d6c2 100644 --- a/src/components/Layout/SaasSelector.tsx +++ b/src/components/Layout/SaasSelector.tsx @@ -1,5 +1,5 @@ import { FormControl, FormErrorMessage, FormLabel, Text } from '@chakra-ui/react' -import { ChakraStylesConfig, GroupBase, Select, Props as SelectProps } from 'chakra-react-select' +import { ChakraStylesConfig, GroupBase, Props as SelectProps, Select } from 'chakra-react-select' import { Controller, useFormContext } from 'react-hook-form' import { ControllerProps } from 'react-hook-form/dist/types' import { useTranslation } from 'react-i18next' @@ -90,6 +90,15 @@ export const SelectCustom = ({ render={({ field }) => (