-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Multiple organization support (#939)
* refs #937 feat: implement signer address persistence in useAuthProvider - Add SignerAddress to LocalStorageKeys - Store and retrieve signer address from localStorage - Use stored address if available, otherwise use first address - Clear stored address on logout * Switch organizations - Fixed organization type incorrectly having name and description - Updated components due to the previous change - Added an organization selector for people having more than one org - Made required changes to properly change the signer between organization changes - Updated organization creation form to properly manage multiple organizations creation - Removed check in previous section to ensure you can always create an org, even having one already refs #937 * refs #937 Move organization switcher logic to its own component * Show organization name in OrganizationSwitcher refs #937 * refs #937 refactor: fetch organization names upfront to avoid re-renders in select dropdown * refs #937 Properly redirect to /admin on success after creating new org * refs #937 Add button to create new orgs in the menu * refs #937 Fixed translation for color mode switcher
- Loading branch information
1 parent
db39f67
commit 0339b2c
Showing
9 changed files
with
207 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { Box, IconButton } from '@chakra-ui/react' | ||
import { PlusSquare } from '@untitled-ui/icons-react' | ||
import { OrganizationName } from '@vocdoni/chakra-components' | ||
import { useClient } from '@vocdoni/react-providers' | ||
import { Select } from 'chakra-react-select' | ||
import { useEffect, useMemo, useState } from 'react' | ||
import { useTranslation } from 'react-i18next' | ||
import { Link } from 'react-router-dom' | ||
import { useQueryClient } from 'wagmi' | ||
import { useAuth } from '~components/Auth/useAuth' | ||
import { LocalStorageKeys } from '~components/Auth/useAuthProvider' | ||
import { Organization, useProfile } from '~src/queries/account' | ||
import { Routes } from '~src/router/routes' | ||
|
||
type SelectOption = { | ||
value: string | ||
label: string | ||
organization: Organization | ||
} | ||
|
||
export const OrganizationSwitcher = () => { | ||
const { t } = useTranslation() | ||
const { data: profile } = useProfile() | ||
const [selectedOrg, setSelectedOrg] = useState<string | null>(localStorage.getItem(LocalStorageKeys.SignerAddress)) | ||
const [names, setNames] = useState<Record<string, string>>({}) | ||
const { signerRefresh } = useAuth() | ||
const queryClient = useQueryClient() | ||
const { client } = useClient() | ||
|
||
// Fetch organization names | ||
useEffect(() => { | ||
if (!profile?.organizations) return | ||
|
||
const fetchOrgNames = async () => { | ||
const names: Record<string, string> = {} | ||
for (const org of profile.organizations) { | ||
const address = org.organization.address | ||
try { | ||
const data = await client.fetchAccount(address) | ||
names[address] = data?.account?.name?.default || address | ||
} catch (error) { | ||
console.error('Error fetching organization name:', error) | ||
names[address] = address | ||
} | ||
} | ||
setNames(names) | ||
} | ||
|
||
fetchOrgNames() | ||
}, [profile]) | ||
|
||
// Populate organizations for the selector | ||
const organizations = useMemo(() => { | ||
if (!profile?.organizations) return [] | ||
return profile.organizations.map((org) => ({ | ||
value: org.organization.address, | ||
label: names[org.organization.address] || org.organization.address, | ||
organization: org.organization, | ||
})) | ||
}, [profile, names]) | ||
|
||
// Set first organization as default if none selected | ||
useEffect(() => { | ||
if (organizations.length && !selectedOrg) { | ||
const firstOrgAddress = organizations[0].value | ||
setSelectedOrg(firstOrgAddress) | ||
localStorage.setItem(LocalStorageKeys.SignerAddress, firstOrgAddress) | ||
} | ||
}, [organizations, selectedOrg]) | ||
|
||
const handleOrgChange = async (option: SelectOption | null) => { | ||
if (!option) return | ||
setSelectedOrg(option.value) | ||
localStorage.setItem(LocalStorageKeys.SignerAddress, option.value) | ||
// clear all query client query cache | ||
queryClient.clear() | ||
// refresh signer | ||
await signerRefresh() | ||
} | ||
|
||
return ( | ||
<Box mb={2} px={3.5} display='flex' alignItems='center' gap={2} justifyContent='space-between'> | ||
{organizations.length > 1 ? ( | ||
<Select | ||
value={organizations.find((org) => org.value === selectedOrg)} | ||
onChange={handleOrgChange} | ||
options={organizations} | ||
size='sm' | ||
chakraStyles={{ | ||
container: (provided) => ({ | ||
...provided, | ||
width: '100%', | ||
}), | ||
}} | ||
/> | ||
) : ( | ||
<OrganizationName mb={2} px={3.5} /> | ||
)} | ||
<IconButton | ||
size='xs' | ||
as={Link} | ||
variant='solid' | ||
colorScheme='gray' | ||
aria-label={t('create_org.title')} | ||
icon={<PlusSquare />} | ||
to={Routes.dashboard.organizationCreate} | ||
/> | ||
</Box> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
0339b2c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π Published on https://vocdoni-app-stg.netlify.app as production
π Deployed on https://678a4ecf830d730f37541a56--vocdoni-app-stg.netlify.app
0339b2c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π Published on https://vocdoni-app-dev.netlify.app as production
π Deployed on https://678a4ed0830d730f37541a5a--vocdoni-app-dev.netlify.app