mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-04-06 01:25:33 +00:00
Merge branch 'main' into improve-docs
This commit is contained in:
commit
0b7b839cf4
32
examples/README.md
Normal file
32
examples/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Examples
|
||||||
|
Here is a collection of executable examples. Building on each other, they show the features available in the Utipia-ui library.
|
||||||
|
You can run them and try them out locally in the browser.
|
||||||
|
|
||||||
|
## Running the examples
|
||||||
|
|
||||||
|
These examples depend on the `/dist` of the root project. You have to run `npm run build` in the root project before you can run the examples:
|
||||||
|
|
||||||
|
Using the example [3 - Tags](./3-tags):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# in root directory install and build the library
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# change to specific example directory
|
||||||
|
cd ./examples/3-tags
|
||||||
|
|
||||||
|
# install and run the example code
|
||||||
|
npm install && npm run dev
|
||||||
|
|
||||||
|
# call up the running example in the browser at http://localhost:5173/
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
- [x] Basic Map
|
||||||
|
- [x] Static Layers
|
||||||
|
- [x] Tags Custom Views & Forms
|
||||||
|
- [ ] APIs Integration
|
||||||
|
- [ ] Permissions
|
||||||
|
- [ ] Custom Views & Forms
|
||||||
|
- [ ] AppShell
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "utopia-ui",
|
"name": "utopia-ui",
|
||||||
"version": "3.0.80",
|
"version": "3.0.81",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "utopia-ui",
|
"name": "utopia-ui",
|
||||||
"version": "3.0.80",
|
"version": "3.0.81",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
"test:component": "cypress run --component --browser electron",
|
"test:component": "cypress run --component --browser electron",
|
||||||
"test:unit": "npm run test:unit:dev -- run --coverage",
|
"test:unit": "npm run test:unit:dev -- run --coverage",
|
||||||
"test:unit:dev": "vitest",
|
"test:unit:dev": "vitest",
|
||||||
|
"test:unit:update": "npm run test:unit:dev -- run --coverage -u",
|
||||||
"docs:generate": "typedoc --includeVersion --navigation.includeCategories true --plugin typedoc-plugin-missing-exports --plugin typedoc-plugin-coverage src/index.tsx",
|
"docs:generate": "typedoc --includeVersion --navigation.includeCategories true --plugin typedoc-plugin-missing-exports --plugin typedoc-plugin-coverage src/index.tsx",
|
||||||
"update": "npx npm-check-updates"
|
"update": "npx npm-check-updates"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -14,16 +14,22 @@ export function AppShell({
|
|||||||
children,
|
children,
|
||||||
assetsApi,
|
assetsApi,
|
||||||
embedded,
|
embedded,
|
||||||
|
openCollectiveApiKey,
|
||||||
}: {
|
}: {
|
||||||
appName: string
|
appName: string
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
assetsApi: AssetsApi
|
assetsApi: AssetsApi
|
||||||
embedded?: boolean
|
embedded?: boolean
|
||||||
|
openCollectiveApiKey?: string
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<ContextWrapper>
|
<ContextWrapper>
|
||||||
<div className='tw-flex tw-flex-col tw-h-full'>
|
<div className='tw-flex tw-flex-col tw-h-full'>
|
||||||
<SetAppState assetsApi={assetsApi} embedded={embedded} />
|
<SetAppState
|
||||||
|
assetsApi={assetsApi}
|
||||||
|
embedded={embedded}
|
||||||
|
openCollectiveApiKey={openCollectiveApiKey}
|
||||||
|
/>
|
||||||
<NavBar appName={appName}></NavBar>
|
<NavBar appName={appName}></NavBar>
|
||||||
<div id='app-content' className='tw-flex'>
|
<div id='app-content' className='tw-flex'>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -7,9 +7,11 @@ import type { AssetsApi } from '#types/AssetsApi'
|
|||||||
export const SetAppState = ({
|
export const SetAppState = ({
|
||||||
assetsApi,
|
assetsApi,
|
||||||
embedded,
|
embedded,
|
||||||
|
openCollectiveApiKey,
|
||||||
}: {
|
}: {
|
||||||
assetsApi: AssetsApi
|
assetsApi: AssetsApi
|
||||||
embedded?: boolean
|
embedded?: boolean
|
||||||
|
openCollectiveApiKey?: string
|
||||||
}) => {
|
}) => {
|
||||||
const setAppState = useSetAppState()
|
const setAppState = useSetAppState()
|
||||||
|
|
||||||
@ -21,5 +23,9 @@ export const SetAppState = ({
|
|||||||
setAppState({ embedded })
|
setAppState({ embedded })
|
||||||
}, [embedded, setAppState])
|
}, [embedded, setAppState])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAppState({ openCollectiveApiKey })
|
||||||
|
}, [openCollectiveApiKey, setAppState])
|
||||||
|
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ interface AppState {
|
|||||||
sideBarOpen: boolean
|
sideBarOpen: boolean
|
||||||
sideBarSlim: boolean
|
sideBarSlim: boolean
|
||||||
embedded: boolean
|
embedded: boolean
|
||||||
|
openCollectiveApiKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type UseAppManagerResult = ReturnType<typeof useAppManager>
|
type UseAppManagerResult = ReturnType<typeof useAppManager>
|
||||||
@ -18,6 +19,7 @@ const initialAppState: AppState = {
|
|||||||
sideBarOpen: false,
|
sideBarOpen: false,
|
||||||
sideBarSlim: false,
|
sideBarSlim: false,
|
||||||
embedded: false,
|
embedded: false,
|
||||||
|
openCollectiveApiKey: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppContext = createContext<UseAppManagerResult>({
|
const AppContext = createContext<UseAppManagerResult>({
|
||||||
|
|||||||
44
src/Components/Profile/ItemFunctions.spec.tsx
Normal file
44
src/Components/Profile/ItemFunctions.spec.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { describe, it, expect, vi } from 'vitest'
|
||||||
|
|
||||||
|
import { linkItem } from './itemFunctions'
|
||||||
|
|
||||||
|
const toastErrorMock: (t: string) => void = vi.fn()
|
||||||
|
const toastSuccessMock: (t: string) => void = vi.fn()
|
||||||
|
|
||||||
|
vi.mock('react-toastify', () => ({
|
||||||
|
toast: {
|
||||||
|
error: (t: string) => toastErrorMock(t),
|
||||||
|
success: (t: string) => toastSuccessMock(t),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('linkItem', () => {
|
||||||
|
const id = 'some-id'
|
||||||
|
let updateApi: () => void = vi.fn()
|
||||||
|
const item = { layer: { api: { updateItem: () => updateApi() } } }
|
||||||
|
const updateItem = vi.fn()
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
updateApi = vi.fn()
|
||||||
|
vi.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('api rejects', () => {
|
||||||
|
it('toasts an error', async () => {
|
||||||
|
updateApi = vi.fn().mockRejectedValue('autsch')
|
||||||
|
await linkItem(id, item, updateItem)
|
||||||
|
expect(toastErrorMock).toHaveBeenCalledWith('autsch')
|
||||||
|
expect(updateItem).not.toHaveBeenCalled()
|
||||||
|
expect(toastSuccessMock).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('api resolves', () => {
|
||||||
|
it('toasts success and calls updateItem()', async () => {
|
||||||
|
await linkItem(id, item, updateItem)
|
||||||
|
expect(toastErrorMock).not.toHaveBeenCalled()
|
||||||
|
expect(updateItem).toHaveBeenCalledTimes(1)
|
||||||
|
expect(toastSuccessMock).toHaveBeenCalledWith('Item linked')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -45,6 +45,7 @@ export function ProfileForm() {
|
|||||||
relations: [] as Item[],
|
relations: [] as Item[],
|
||||||
start: '',
|
start: '',
|
||||||
end: '',
|
end: '',
|
||||||
|
openCollectiveSlug: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const [updatePermission, setUpdatePermission] = useState<boolean>(false)
|
const [updatePermission, setUpdatePermission] = useState<boolean>(false)
|
||||||
@ -137,6 +138,7 @@ export function ProfileForm() {
|
|||||||
relations,
|
relations,
|
||||||
start: item.start ?? '',
|
start: item.start ?? '',
|
||||||
end: item.end ?? '',
|
end: item.end ?? '',
|
||||||
|
openCollectiveSlug: item.openCollectiveSlug ?? '',
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [item, tags, items])
|
}, [item, tags, items])
|
||||||
|
|||||||
38
src/Components/Profile/Subcomponents/CrowdfundingForm.tsx
Normal file
38
src/Components/Profile/Subcomponents/CrowdfundingForm.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
|
import { TextInput } from '#components/Input'
|
||||||
|
|
||||||
|
import type { FormState } from '#types/FormState'
|
||||||
|
|
||||||
|
export const CrowdfundingForm = ({
|
||||||
|
state,
|
||||||
|
setState,
|
||||||
|
}: {
|
||||||
|
state: FormState
|
||||||
|
setState: React.Dispatch<React.SetStateAction<any>>
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className='tw-mt-4 tw-space-y-4'>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
htmlFor='OpenCollectiveSlug'
|
||||||
|
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||||
|
>
|
||||||
|
Open Collective Slug:
|
||||||
|
</label>
|
||||||
|
<TextInput
|
||||||
|
placeholder='Open Collective Slug'
|
||||||
|
type='text'
|
||||||
|
required={false}
|
||||||
|
defaultValue={state.openCollectiveSlug}
|
||||||
|
updateFormValue={(v) =>
|
||||||
|
setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
openCollectiveSlug: v,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
192
src/Components/Profile/Subcomponents/CrowdfundingView.tsx
Normal file
192
src/Components/Profile/Subcomponents/CrowdfundingView.tsx
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
||||||
|
|
||||||
|
import type { Item } from '#types/Item'
|
||||||
|
|
||||||
|
interface AccountData {
|
||||||
|
account: {
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
stats: {
|
||||||
|
balance: {
|
||||||
|
valueInCents: number
|
||||||
|
currency: string
|
||||||
|
} | null
|
||||||
|
totalAmountReceived: {
|
||||||
|
valueInCents: number
|
||||||
|
currency: string
|
||||||
|
}
|
||||||
|
totalAmountSpent: {
|
||||||
|
valueInCents: number
|
||||||
|
currency: string
|
||||||
|
}
|
||||||
|
contributionsCount: number
|
||||||
|
contributorsCount: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GraphQLResponse<T> {
|
||||||
|
data?: T
|
||||||
|
errors?: { message: string }[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const GET_TRANSACTIONS = `
|
||||||
|
query GetAccountStats($slug: String!) {
|
||||||
|
account(slug: $slug) {
|
||||||
|
name
|
||||||
|
type
|
||||||
|
stats {
|
||||||
|
balance {
|
||||||
|
valueInCents
|
||||||
|
currency
|
||||||
|
}
|
||||||
|
totalAmountReceived(net: true) {
|
||||||
|
valueInCents
|
||||||
|
currency
|
||||||
|
}
|
||||||
|
totalAmountSpent {
|
||||||
|
valueInCents
|
||||||
|
currency
|
||||||
|
}
|
||||||
|
contributionsCount
|
||||||
|
contributorsCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const formatCurrency = (valueInCents: number, currency: string) => {
|
||||||
|
const value = valueInCents / 100
|
||||||
|
const options: Intl.NumberFormatOptions = {
|
||||||
|
style: 'currency',
|
||||||
|
currency,
|
||||||
|
...(Math.abs(value) >= 1000 ? { minimumFractionDigits: 0, maximumFractionDigits: 0 } : {}),
|
||||||
|
}
|
||||||
|
return new Intl.NumberFormat('de-DE', options).format(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CrowdfundingView = ({ item }: { item: Item }) => {
|
||||||
|
// Hier wird slug aus dem Item extrahiert.
|
||||||
|
const slug = item.openCollectiveSlug
|
||||||
|
const appState = useAppState()
|
||||||
|
|
||||||
|
const token = appState.openCollectiveApiKey
|
||||||
|
|
||||||
|
const graphqlClient = axios.create({
|
||||||
|
baseURL: 'https://api.opencollective.com/graphql/v2',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const [data, setData] = useState<AccountData | null>(null)
|
||||||
|
const [loading, setLoading] = useState<boolean>(true)
|
||||||
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
setError(null)
|
||||||
|
try {
|
||||||
|
const response = await graphqlClient.post<GraphQLResponse<AccountData>>('', {
|
||||||
|
query: GET_TRANSACTIONS,
|
||||||
|
variables: { slug },
|
||||||
|
})
|
||||||
|
if (response.data.errors?.length) {
|
||||||
|
setError(response.data.errors[0].message)
|
||||||
|
} else {
|
||||||
|
setData(response.data.data ?? null)
|
||||||
|
}
|
||||||
|
} catch (err: unknown) {
|
||||||
|
if (err instanceof Error) {
|
||||||
|
setError(err.message)
|
||||||
|
} else {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slug) {
|
||||||
|
void fetchData()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [slug])
|
||||||
|
|
||||||
|
if (!slug) return null
|
||||||
|
|
||||||
|
if (loading)
|
||||||
|
return (
|
||||||
|
<div className='tw-flex tw-justify-center'>
|
||||||
|
<span className='tw-loading tw-loading-spinner tw-loading-lg tw-text-neutral-content'></span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <p className='tw-text-center tw-text-lg tw-text-red-500'>Error: {error}</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data?.account) {
|
||||||
|
return (
|
||||||
|
<p className='tw-text-center tw-text-lg tw-text-red-500'>
|
||||||
|
No data available for this account.
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { stats } = data.account
|
||||||
|
const balanceValueInCents = stats.balance?.valueInCents ?? 0
|
||||||
|
const currency = stats.balance?.currency ?? 'USD'
|
||||||
|
const currentBalance = balanceValueInCents
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='tw-mx-6 tw-mb-6'>
|
||||||
|
<div className='tw-card tw-bg-base-200 tw-w-fit tw-max-w-full tw-shadow'>
|
||||||
|
<div className='tw-stats tw-bg-base-200 tw-stats-horizontal tw-rounded-b-none'>
|
||||||
|
<div className='tw-stat tw-p-3'>
|
||||||
|
<div className='tw-stat-title'>Current Balance</div>
|
||||||
|
<div className='tw-stat-value tw-text-xl lg:tw-text-3xl'>
|
||||||
|
{formatCurrency(currentBalance, currency)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='tw-stat tw-p-3'>
|
||||||
|
<div className='tw-stat-title'>Received</div>
|
||||||
|
<div className='tw-stat-value tw-text-green-500 tw-text-xl lg:tw-text-3xl'>
|
||||||
|
{formatCurrency(stats.totalAmountReceived.valueInCents, currency)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='tw-stat tw-p-3'>
|
||||||
|
<div className='tw-stat-title'>Spent</div>
|
||||||
|
<div className='tw-stat-value tw-text-red-500 tw-text-xl lg:tw-text-3xl'>
|
||||||
|
{formatCurrency(stats.totalAmountReceived.valueInCents - currentBalance, currency)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr></hr>
|
||||||
|
<div className='tw-m-4 tw-items-center'>
|
||||||
|
<a href={`https://opencollective.com/${slug}/donate`} target='_blank' rel='noreferrer'>
|
||||||
|
<button className='tw-btn tw-btn-sm tw-btn-primary tw-float-right tw-ml-4'>
|
||||||
|
Donate
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
<div className='tw-flex-1 tw-mr-4'>
|
||||||
|
Support{' '}
|
||||||
|
<a
|
||||||
|
className='tw-font-bold'
|
||||||
|
href={`https://opencollective.com/${slug}`}
|
||||||
|
target='_blank'
|
||||||
|
rel='noreferrer'
|
||||||
|
>
|
||||||
|
{data.account.name}
|
||||||
|
</a>{' '}
|
||||||
|
on <span className='tw-font-bold'>Open Collective</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
|
||||||
import { ContactInfoForm } from '#components/Profile/Subcomponents/ContactInfoForm'
|
import { ContactInfoForm } from '#components/Profile/Subcomponents/ContactInfoForm'
|
||||||
|
import { CrowdfundingForm } from '#components/Profile/Subcomponents/CrowdfundingForm'
|
||||||
import { GroupSubheaderForm } from '#components/Profile/Subcomponents/GroupSubheaderForm'
|
import { GroupSubheaderForm } from '#components/Profile/Subcomponents/GroupSubheaderForm'
|
||||||
import { ProfileStartEndForm } from '#components/Profile/Subcomponents/ProfileStartEndForm'
|
import { ProfileStartEndForm } from '#components/Profile/Subcomponents/ProfileStartEndForm'
|
||||||
import { ProfileTextForm } from '#components/Profile/Subcomponents/ProfileTextForm'
|
import { ProfileTextForm } from '#components/Profile/Subcomponents/ProfileTextForm'
|
||||||
@ -14,6 +15,7 @@ const componentMap = {
|
|||||||
texts: ProfileTextForm,
|
texts: ProfileTextForm,
|
||||||
contactInfos: ContactInfoForm,
|
contactInfos: ContactInfoForm,
|
||||||
startEnd: ProfileStartEndForm,
|
startEnd: ProfileStartEndForm,
|
||||||
|
crowdfundings: CrowdfundingForm,
|
||||||
// weitere Komponenten hier
|
// weitere Komponenten hier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
|
||||||
import { ContactInfoView } from '#components/Profile/Subcomponents/ContactInfoView'
|
import { ContactInfoView } from '#components/Profile/Subcomponents/ContactInfoView'
|
||||||
|
import { CrowdfundingView } from '#components/Profile/Subcomponents/CrowdfundingView'
|
||||||
import { GalleryView } from '#components/Profile/Subcomponents/GalleryView'
|
import { GalleryView } from '#components/Profile/Subcomponents/GalleryView'
|
||||||
import { GroupSubHeaderView } from '#components/Profile/Subcomponents/GroupSubHeaderView'
|
import { GroupSubHeaderView } from '#components/Profile/Subcomponents/GroupSubHeaderView'
|
||||||
import { ProfileStartEndView } from '#components/Profile/Subcomponents/ProfileStartEndView'
|
import { ProfileStartEndView } from '#components/Profile/Subcomponents/ProfileStartEndView'
|
||||||
@ -15,6 +16,7 @@ const componentMap = {
|
|||||||
contactInfos: ContactInfoView,
|
contactInfos: ContactInfoView,
|
||||||
startEnd: ProfileStartEndView,
|
startEnd: ProfileStartEndView,
|
||||||
gallery: GalleryView,
|
gallery: GalleryView,
|
||||||
|
crowdfundings: CrowdfundingView,
|
||||||
// weitere Komponenten hier
|
// weitere Komponenten hier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -196,6 +196,7 @@ export const onUpdateItem = async (
|
|||||||
...(state.image.length > 10 && { image: state.image }),
|
...(state.image.length > 10 && { image: state.image }),
|
||||||
...(state.offers.length > 0 && { offers: offerUpdates }),
|
...(state.offers.length > 0 && { offers: offerUpdates }),
|
||||||
...(state.needs.length > 0 && { needs: needsUpdates }),
|
...(state.needs.length > 0 && { needs: needsUpdates }),
|
||||||
|
...(state.openCollectiveSlug && { openCollectiveSlug: state.openCollectiveSlug }),
|
||||||
}
|
}
|
||||||
|
|
||||||
const offersState: any[] = []
|
const offersState: any[] = []
|
||||||
|
|||||||
1
src/types/FormState.d.ts
vendored
1
src/types/FormState.d.ts
vendored
@ -19,4 +19,5 @@ export interface FormState {
|
|||||||
relations: Item[]
|
relations: Item[]
|
||||||
start: string
|
start: string
|
||||||
end: string
|
end: string
|
||||||
|
openCollectiveSlug: string
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/types/Item.d.ts
vendored
1
src/types/Item.d.ts
vendored
@ -50,6 +50,7 @@ export interface Item {
|
|||||||
telephone?: string
|
telephone?: string
|
||||||
next_appointment?: string
|
next_appointment?: string
|
||||||
gallery?: GalleryItem[]
|
gallery?: GalleryItem[]
|
||||||
|
openCollectiveSlug?: string
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// coordinates: [number, number]
|
// coordinates: [number, number]
|
||||||
|
|||||||
@ -16,9 +16,6 @@ export default defineConfig({
|
|||||||
reporter: ['html', 'json-summary'],
|
reporter: ['html', 'json-summary'],
|
||||||
thresholds: {
|
thresholds: {
|
||||||
lines: 1,
|
lines: 1,
|
||||||
functions: 56,
|
|
||||||
branches: 58,
|
|
||||||
statements: 1,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user