Skip to content

Commit

Permalink
Merge branch 'main' into regulations-admin/styling-and-presigned
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Sep 16, 2024
2 parents 535628f + eb982d4 commit 4edff74
Show file tree
Hide file tree
Showing 15 changed files with 494 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const GenericListEditor = () => {
skip,
'fields.internalTitle[match]': searchValue,
'fields.genericList.sys.id': sdk.entry.getSys().id,
'sys.archivedAt[exists]': false,
},
})
if (
Expand Down
180 changes: 180 additions & 0 deletions apps/contentful-apps/pages/fields/generic-tag-group-items-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { useEffect, useRef, useState } from 'react'
import { useDebounce } from 'react-use'
import type { FieldExtensionSDK } from '@contentful/app-sdk'
import {
Box,
Button,
EntryCard,
Pagination,
Spinner,
Stack,
Text,
TextInput,
} from '@contentful/f36-components'
import { PlusIcon } from '@contentful/f36-icons'
import { useCMA, useSDK } from '@contentful/react-apps-toolkit'

const LIST_ITEMS_PER_PAGE = 4
const SEARCH_DEBOUNCE_TIME_IN_MS = 300

const GenericTagGroupItemsField = () => {
const [page, setPage] = useState(0)
const pageRef = useRef(0)
const [searchValue, setSearchValue] = useState('')
const searchValueRef = useRef('')
const [listItemResponse, setListItemResponse] = useState(null)
const [isLoading, setIsLoading] = useState(false)

const [counter, setCounter] = useState(0)

const sdk = useSDK<FieldExtensionSDK>()
const cma = useCMA()

const skip = LIST_ITEMS_PER_PAGE * page

const createGenericTag = async () => {
const tag = await cma.entry.create(
{
contentTypeId: 'genericTag',
environmentId: sdk.ids.environment,
spaceId: sdk.ids.space,
},
{
fields: {
genericTagGroup: {
[sdk.locales.default]: {
sys: {
id: sdk.entry.getSys().id,
linkType: 'Entry',
type: 'Link',
},
},
},
},
},
)
sdk.navigator
.openEntry(tag.sys.id, {
slideIn: { waitForClose: true },
})
.then(() => {
setCounter((c) => c + 1)
})
}

useDebounce(
async () => {
setIsLoading(true)
try {
const response = await cma.entry.getMany({
query: {
content_type: 'genericTag',
limit: LIST_ITEMS_PER_PAGE,
skip,
'fields.internalTitle[match]': searchValue,
'fields.genericTagGroup.sys.id': sdk.entry.getSys().id,
'sys.archivedAt[exists]': false,
},
})

if (
searchValueRef.current === searchValue &&
pageRef.current === page
) {
setListItemResponse(response)
}
} finally {
setIsLoading(false)
}
},
SEARCH_DEBOUNCE_TIME_IN_MS,
[page, searchValue, counter],
)

useEffect(() => {
sdk.window.startAutoResizer()
return () => {
sdk.window.stopAutoResizer()
}
}, [sdk.window])

return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
<Box>
<Box
onClick={createGenericTag}
style={{ display: 'flex', justifyContent: 'flex-end' }}
>
<Button startIcon={<PlusIcon />}>Create tag</Button>
</Box>
</Box>
<Box style={{ display: 'flex', flexFlow: 'column nowrap', gap: '24px' }}>
<TextInput
placeholder="Search for a generic tag"
value={searchValue}
onChange={(ev) => {
searchValueRef.current = ev.target.value
setSearchValue(ev.target.value)
setPage(0)
pageRef.current = 0
}}
/>

<Box
style={{
display: 'flex',
justifyContent: 'center',
visibility: isLoading ? 'visible' : 'hidden',
}}
>
<Spinner />
</Box>

{listItemResponse?.items?.length > 0 && (
<>
<Box style={{ minHeight: '440px' }}>
<Stack flexDirection="column" spacing="spacingL">
{listItemResponse.items.map((item) => (
<EntryCard
key={item.sys.id}
contentType="Generic Tag"
title={
item.fields.internalTitle?.[sdk.locales.default] ??
'Untitled'
}
onClick={() => {
sdk.navigator
.openEntry(item.sys.id, {
slideIn: { waitForClose: true },
})
.then(() => {
setCounter((c) => c + 1)
})
}}
/>
))}
</Stack>
</Box>
<Pagination
activePage={page}
itemsPerPage={LIST_ITEMS_PER_PAGE}
totalItems={listItemResponse.total}
onPageChange={(newPage) => {
pageRef.current = newPage
setPage(newPage)
}}
/>
</>
)}

{listItemResponse?.items?.length === 0 && (
<Box style={{ display: 'flex', justifyContent: 'center' }}>
<Text>No item was found</Text>
</Box>
)}
</Box>
</div>
)
}

export default GenericTagGroupItemsField
193 changes: 193 additions & 0 deletions apps/contentful-apps/pages/fields/team-member-filter-tags-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { useEffect, useState } from 'react'
import { useDebounce } from 'react-use'
import {
CollectionProp,
EntryProps,
KeyValueMap,
QueryOptions,
SysLink,
} from 'contentful-management'
import type { CMAClient, FieldExtensionSDK } from '@contentful/app-sdk'
import { Checkbox, Spinner, Stack, Text } from '@contentful/f36-components'
import { useCMA, useSDK } from '@contentful/react-apps-toolkit'

import { sortAlpha } from '@island.is/shared/utils'

const DEBOUNCE_TIME = 500

const fetchAll = async (cma: CMAClient, query: QueryOptions) => {
let response: CollectionProp<EntryProps<KeyValueMap>> | null = null
const items: EntryProps<KeyValueMap>[] = []
let limit = 100

while ((response === null || items.length < response.total) && limit > 0) {
try {
response = await cma.entry.getMany({
query: {
...query,
limit,
skip: items.length,
},
})
items.push(...response.items)
} catch (error) {
const isResponseTooBig = (error?.message as string)
?.toLowerCase()
?.includes('response size too big')

if (isResponseTooBig) limit = Math.floor(limit / 2)
else throw error
}
}

return items
}

const TeamMemberFilterTagsField = () => {
const sdk = useSDK<FieldExtensionSDK>()
const cma = useCMA()
const [isLoading, setIsLoading] = useState(true)

const [filterTagSysLinks, setFilterTagSysLinks] = useState<SysLink[]>(
sdk.field.getValue() ?? [],
)

const [tagGroups, setTagGroups] = useState<
{
tagGroup: EntryProps<KeyValueMap>
tags: EntryProps<KeyValueMap>[]
}[]
>([])

useEffect(() => {
sdk.window.startAutoResizer()
return () => {
sdk.window.stopAutoResizer()
}
}, [sdk.window])

useEffect(() => {
const fetchTeamList = async () => {
try {
const teamListResponse = await cma.entry.getMany({
query: {
links_to_entry: sdk.entry.getSys().id,
content_type: 'teamList',
},
})

if (teamListResponse.items.length === 0) {
setIsLoading(false)
return
}

const tagGroupSysLinks: SysLink[] =
teamListResponse.items[0].fields.filterGroups?.[
sdk.locales.default
] ?? []

const promises = tagGroupSysLinks.map(async (tagGroupSysLink) => {
const [tagGroup, tags] = await Promise.all([
cma.entry.get({
entryId: tagGroupSysLink.sys.id,
}),
fetchAll(cma, {
links_to_entry: tagGroupSysLink.sys.id,
content_type: 'genericTag',
}),
])

tags.sort((a, b) => {
return sortAlpha(sdk.locales.default)(
a.fields.title,
b.fields.title,
)
})

return { tagGroup, tags }
})

setTagGroups(await Promise.all(promises))
} finally {
setIsLoading(false)
}
}

fetchTeamList()
}, [cma, sdk.entry, sdk.locales.default, setTagGroups])

useDebounce(
() => {
sdk.field.setValue(filterTagSysLinks)
},
DEBOUNCE_TIME,
[filterTagSysLinks],
)

return (
<>
{isLoading && <Spinner />}

{!isLoading && (
<Stack
flexDirection="column"
alignItems="flex-start"
spacing="spacing2Xl"
>
{tagGroups.map(({ tagGroup, tags }) => {
return (
<Stack
key={tagGroup.sys.id}
flexDirection="column"
alignItems="flex-start"
>
<Text fontSize="fontSizeL" fontWeight="fontWeightDemiBold">
{tagGroup.fields.title[sdk.locales.default]}
</Text>
<Stack flexDirection="column" alignItems="flex-start">
{tags.map((tag) => {
const isChecked = filterTagSysLinks.some(
(filterTagSysLink) =>
filterTagSysLink.sys.id === tag.sys.id,
)
return (
<Checkbox
key={tag.sys.id}
isChecked={isChecked}
onChange={() => {
setFilterTagSysLinks((prev) => {
const alreadyExists = prev.some(
(filterTagSysLink) =>
filterTagSysLink.sys.id === tag.sys.id,
)
if (alreadyExists) {
return prev.filter(
(filterTagSysLink) =>
filterTagSysLink.sys.id !== tag.sys.id,
)
}
return prev.concat({
sys: {
id: tag.sys.id,
type: 'Link',
linkType: 'Entry',
},
})
})
}}
>
{tag.fields.title[sdk.locales.default]}
</Checkbox>
)
})}
</Stack>
</Stack>
)
})}
</Stack>
)}
</>
)
}

export default TeamMemberFilterTagsField
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ const CaseFileTable: FC<Props> = ({
</td>
<td>
<Box className={styles.noWrapColumn}>
<Text textAlign="right">
<Text>
{formatDate(file.created, "dd.MM.yyyy 'kl.' HH:mm")}
</Text>
<Text variant="small" textAlign="right">
<Text variant="small">
{formatMessage(strings.submittedBy, {
category: file.category,
initials: getInitials(file.submittedBy),
Expand Down
Loading

0 comments on commit 4edff74

Please sign in to comment.