Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move most actions logic to react-providers #110

Merged
merged 1 commit into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/chakra-components/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ const App = () => {

> Beware that you'll also see a `ClientProvider` also from
> `@vocdoni/react-providers`. You should always be using the one included with
> chakra components in order to have all the features they provide.
> `@vocdoni/chakra-components` in order to have all the features it provides.
>
> Note this also happens with other components and providers. If you are using
> `@vocdoni/chakra-components`, you should always prioritize its exports over
> the ones from `@vocdoni/react-providers`.

Note `env` can be any of the [SDK available environments][sdk environments],
either in string format, or using the SDK `EnvOptions` enum.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ButtonGroup, IconButton } from '@chakra-ui/button'
import { ChakraProps, chakra, useMultiStyleConfig } from '@chakra-ui/system'
import { chakra, ChakraProps, useMultiStyleConfig } from '@chakra-ui/system'
import { useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings } from '@vocdoni/sdk'
import { FaPause, FaPlay, FaStop } from 'react-icons/fa'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
import { PropsWithChildren, createContext, useContext } from 'react'
import { useActionsProvider } from './use-actions-provider'

export type ActionsState = ReturnType<typeof useActionsProvider>

export const ActionsContext = createContext<ActionsState | undefined>(undefined)

export const useActions = () => {
const ctxt = useContext(ActionsContext)
if (!ctxt) {
throw new Error(
'useActions returned `undefined`, maybe you forgot to wrap the component within <ActionsProvider />?'
)
}

return ctxt
import { ActionsProvider as RActionsProvider } from '@vocdoni/react-providers'
import { PropsWithChildren, ReactElement } from 'react'
import { useActionsToast } from './use-actions-toast'

export const ActionsProvider = (props: PropsWithChildren) => {
return (
<RActionsProvider>
<ChakraInternalActionsProvider {...props} />
</RActionsProvider>
)
}

export type ActionsProviderComponentProps = PropsWithChildren

export const ActionsProvider = ({ children }: ActionsProviderComponentProps) => {
const value = useActionsProvider()
// We need to define an "internal" component in order to be able to use the
// hooks, otherwise they wouldn't have access to the ActionsProvider context
const ChakraInternalActionsProvider = ({ children }: PropsWithChildren) => {
useActionsToast()

return <ActionsContext.Provider value={value}>{children}</ActionsContext.Provider>
return children as ReactElement
}

ActionsProvider.displayName = 'ActionsProvider'
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { useClient, useElection } from '@vocdoni/react-providers'
import { ElectionStatus, areEqualHexStrings } from '@vocdoni/sdk'
import { useActions } from './ActionsProvider'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'

export const ActionCancel = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { useClient, useElection } from '@vocdoni/react-providers'
import { ElectionStatus, areEqualHexStrings } from '@vocdoni/sdk'
import { useActions } from './ActionsProvider'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'

export const ActionContinue = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { useClient, useElection } from '@vocdoni/react-providers'
import { ElectionStatus, areEqualHexStrings } from '@vocdoni/sdk'
import { useActions } from './ActionsProvider'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'

export const ActionEnd = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { useClient, useElection } from '@vocdoni/react-providers'
import { ElectionStatus, areEqualHexStrings } from '@vocdoni/sdk'
import { useActions } from './ActionsProvider'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'

export const ActionPause = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ToastId, useToast } from '@chakra-ui/toast'
import { useActions } from '@vocdoni/react-providers'
import { useEffect, useRef } from 'react'

export const useActionsToast = () => {
const tRef = useRef<ToastId>()
const { info, error } = useActions()
const toast = useToast()

// show toasts for info and error
useEffect(() => {
if (toast && info === null && tRef.current) {
toast.close(tRef.current)
}
if (info && toast) {
tRef.current = toast({
title: info.title,
description: info.description,
status: 'info',
duration: null,
isClosable: false,
})
}
if (error && toast) {
toast({
title: error.title,
description: error.description,
status: 'error',
duration: 7000,
isClosable: false,
})
}
}, [info, error, toast])
}
78 changes: 73 additions & 5 deletions packages/react-providers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The very first step is to add the `<ClientProvider />` as a wrapper of your
application or, at least, of your election:

~~~tsx
import { ClientProvider } from '@vocdoni/chakra-components'
import { ClientProvider } from '@vocdoni/react-providers'

const App = () => {
const signer = /* any ethers based signer */
Expand All @@ -35,13 +35,81 @@ const App = () => {
`ClientProvider` is a dependency of the other providers, so you'll have to
ensure you initialize that one as the parent.

### ElectionProvider

The `ElectionProvider` is the one that will allow you to interact with the
election and easily execute actions like voting.

You can use it as a wrapper of your elections:

~~~tsx
import { ElectionProvider } from '@vocdoni/react-providers'

const MyElection = () => {
return (
<ElectionProvider id='election-uuid'>
{/* your actual election code */}
</ElectionProvider>
)
}
~~~

You can either specify an id, and the provider will fetch the election for you,
or you can directly pass an `election` object. This is usefull in case you want
to render a list of elections and you already have the data:

~~~tsx
import { ElectionProvider } from '@vocdoni/react-providers'

const MyElectionList = () => {
const elections = /* your elections list */
return (
elections.map((election)=> (
<ElectionProvider election={election}>
<MyElectionListItem />
</ElectionProvider>
))
)
}
~~~

Once you initialized the provider, you can use the `useElection` hook to
interact with the election:


~~~tsx
import { useElection } from '@vocdoni/react-providers'

const MyElectionListItem = () => {
const { election } = useElection()

return <h1>{election.title.default}</h1>
}
~~~

### OrganizationProvider

Works more or less the same as the `ElectionProvider`, but for organizations:

~~~tsx
import { OrganizationProvider } from '@vocdoni/react-providers'

const MyElection = () => {
return (
<OrganizationProvider id='organization-uuid'>
{/* your actual organization code */}
</OrganizationProvider>
)
}
~~~

### hooks

- `useClient` allows you to interact with the `ClientProvider` layer. All the
methods it exports allow you to use the client while interacting with the
context/state:
+ `fetchAccount`
+ `createAccount`
+ `fetchAccount`: fetches connected account information (and balance)
+ `createAccount`: creates a new account using the connected signer
+ `setClient`: allows you to change the client during runtime
+ `localize`: internal method used for localization
+ `setSigner`: allows you to change the signer during runtime
Expand All @@ -53,8 +121,8 @@ ensure you initialize that one as the parent.
(used by flows like the spreadsheet/csv login one)
+ `vote`: A helper method to vote, using the current context info.
- `useOrganization`:
+ `fetch`
+ `update`
+ `fetch`: fetches the organization data
+ `update`: update the organization (only for organization owners)

License
-------
Expand Down
Loading