Skip to content

Commit

Permalink
chore(tags): tags colors (#1578)
Browse files Browse the repository at this point in the history
* chore(tags): set of colors and refactoring

* chore(boards): refactor

* chore(tags): tailwind config

* chore(tags): tokens

* fix(tags): fix tags able to be empty string

* chore(tags): colors constant

* chore(tags): rename variable
  • Loading branch information
oyvindgrutle authored Jul 19, 2024
1 parent c8cdb1f commit 4a0d508
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 140 deletions.
2 changes: 1 addition & 1 deletion next-tavla/app/(admin)/boards/components/Column/Delete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { Heading2, Paragraph } from '@entur/typography'
import { HiddenInput } from 'components/Form/HiddenInput'
import { FormError } from 'app/(admin)/components/FormError'
import { useFormState } from 'react-dom'
import { deleteBoardAction } from '../../utils/formActions'
import { getFormFeedbackForField } from 'app/(admin)/utils'
import sheep from 'assets/illustrations/Sheep.png'
import Image from 'next/image'
import { SubmitButton } from 'components/Form/SubmitButton'
import { OverflowMenuItem } from '@entur/menu'
import { useToast } from '@entur/alert'
import { deleteBoardAction } from '../../utils/actions'

function Delete({
board,
Expand Down
33 changes: 18 additions & 15 deletions next-tavla/app/(admin)/boards/components/Column/Tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,24 @@ import { useSearchParam } from '../../hooks/useSearchParam'
function TagList({ tags, children }: { tags: TTag[]; children?: ReactNode }) {
return (
<ul className="flex flex-row flex-wrap gap-1 items-center">
{tags.map((tag) => (
<li key={tag}>
<Badge
variant="primary"
type="notification"
style={{
backgroundColor: colorsFromHash(tag),
borderColor: colorsFromHash(tag),
}}
>
<span className="visuallyHidden">Merkelapp:</span>
{tag}
</Badge>
</li>
))}
{tags.map((tag) => {
const color = colorsFromHash(tag)
return (
<li key={tag}>
<Badge
variant="primary"
type="status"
style={{
backgroundColor: color,
borderColor: color,
}}
>
<span className="visuallyHidden">Merkelapp:</span>
{tag}
</Badge>
</li>
)
})}
{children}
</ul>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import { difference } from 'lodash'
import { ActionChip } from '@entur/chip'
import { AddIcon } from '@entur/icons'
import { Heading3 } from '@entur/typography'
import { addTagAction } from '../../utils/formActions'
import { HiddenInput } from 'components/Form/HiddenInput'
import { TBoard, TBoardID } from 'types/settings'
import { useFormState, useFormStatus } from 'react-dom'
import { useTags } from '../../utils/context'
import { FormError } from 'app/(admin)/components/FormError'
import { getFormFeedbackForField } from 'app/(admin)/utils'
import { TTag } from 'types/meta'
import { addTag } from './actions'

function AddExistingTag({ board }: { board: TBoard }) {
const allTags = useTags()
const existingTags = difference(allTags, board.meta?.tags ?? [])
const [state, action] = useFormState(addTagAction, undefined)
const [state, action] = useFormState(addTag, undefined)

return (
<div className="flex flex-col gap-1">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Heading3 } from '@entur/typography'
import { TextField } from '@entur/form'
import { addTagAction } from '../../utils/formActions'
import { HiddenInput } from 'components/Form/HiddenInput'
import { TBoard } from 'types/settings'
import { useFormState } from 'react-dom'
import { FormError } from 'app/(admin)/components/FormError'
import { getFormFeedbackForField } from 'app/(admin)/utils'
import { useRef } from 'react'
import { SubmitButton } from 'components/Form/SubmitButton'
import { addTag } from './actions'

function AddNewTag({ board }: { board: TBoard }) {
const [state, action] = useFormState(addTagAction, undefined)
const [state, action] = useFormState(addTag, undefined)
const form = useRef<HTMLFormElement>(null)

const submit = async (data: FormData) => {
Expand Down
75 changes: 75 additions & 0 deletions next-tavla/app/(admin)/boards/components/TagModal/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use server'
import { TFormFeedback, getFormFeedbackForError } from 'app/(admin)/utils'
import { FirebaseError } from 'firebase/app'
import { isString, uniq } from 'lodash'
import { revalidatePath } from 'next/cache'
import { hasBoardEditorAccess } from 'app/(admin)/utils/firebase'
import { TBoardID } from 'types/settings'
import { firestore } from 'firebase-admin'
import { TTag } from 'types/meta'
import { isEmptyOrSpaces } from 'app/(admin)/edit/utils'

async function fetchTags({ bid }: { bid: TBoardID }) {
const board = await firestore().collection('boards').doc(bid).get()
if (!board.exists) throw 'board/not-found'

const access = await hasBoardEditorAccess(board.id)
if (!access) throw 'auth/operation-not-allowed'

return (board.data()?.meta?.tags as TTag[]) ?? []
}

export async function removeTag(
prevState: TFormFeedback | undefined,
data: FormData,
) {
const bid = data.get('bid') as string
const tag = data.get('tag') as string

const access = await hasBoardEditorAccess(bid)
if (!access) throw 'auth/operation-not-allowed'

try {
const tags = await fetchTags({ bid })
await firestore()
.collection('boards')
.doc(bid)
.update({ 'meta.tags': tags.filter((t) => t !== tag) })
revalidatePath('/')
} catch (e) {
if (e instanceof FirebaseError || isString(e))
return getFormFeedbackForError(e)
return getFormFeedbackForError('general')
}
}

export async function addTag(
prevState: TFormFeedback | undefined,
data: FormData,
) {
const bid = data.get('bid') as string
const tag = data.get('tag') as string

if (isEmptyOrSpaces(tag))
return getFormFeedbackForError('tags/name-missing')

const access = await hasBoardEditorAccess(bid)
if (!access) throw 'auth/operation-not-allowed'

try {
const tags = await fetchTags({ bid })

if (tags.map((t) => t.toUpperCase()).includes(tag.toUpperCase()))
throw 'boards/tag-exists'

await firestore()
.collection('boards')
.doc(bid)
.update({ 'meta.tags': uniq([...tags, tag]).sort() })
revalidatePath('/')
} catch (e) {
if (e instanceof FirebaseError || isString(e))
return getFormFeedbackForError(e)
return getFormFeedbackForError('general')
}
}
6 changes: 3 additions & 3 deletions next-tavla/app/(admin)/boards/components/TagModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import { IconButton } from '@entur/button'
import { CloseIcon, ReferenceIcon } from '@entur/icons'
import { ActionChip } from '@entur/chip'
import { AddExistingTag } from './AddExistingTag'
import { removeTagAction } from '../../utils/formActions'
import { HiddenInput } from 'components/Form/HiddenInput'
import { useFormState } from 'react-dom'
import { FormError } from 'app/(admin)/components/FormError'
import { getFormFeedbackForField } from 'app/(admin)/utils'
import { useModalWithValue } from '../../hooks/useModalWithValue'
import { DEFAULT_BOARD_NAME } from 'app/(admin)/utils/constants'
import { removeTag } from './actions'

function TagModal({ board }: { board: TBoard }) {
const tags = board.meta?.tags ?? []
const { isOpen, open, close } = useModalWithValue('addTags', board.id ?? '')
const [state, action] = useFormState(removeTagAction, undefined)
const [state, action] = useFormState(removeTag, undefined)
return (
<>
<Tooltip content="Administrer merkelapper" placement="bottom">
Expand Down Expand Up @@ -49,7 +49,7 @@ function TagModal({ board }: { board: TBoard }) {
value={tag}
type="submit"
>
{tag} <CloseIcon />
{tag.toUpperCase()} <CloseIcon />
</ActionChip>
</form>
))}
Expand Down
26 changes: 26 additions & 0 deletions next-tavla/app/(admin)/boards/utils/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use server'
import { TFormFeedback, getFormFeedbackForError } from 'app/(admin)/utils'
import { FirebaseError } from 'firebase/app'
import { isString } from 'lodash'
import { revalidatePath } from 'next/cache'
import { deleteBoard, initializeAdminApp } from 'app/(admin)/utils/firebase'
import { redirect } from 'next/navigation'

initializeAdminApp()

export async function deleteBoardAction(
prevState: TFormFeedback | undefined,
data: FormData,
) {
try {
const bid = data.get('bid') as string

await deleteBoard(bid)
revalidatePath('/')
} catch (e) {
if (e instanceof FirebaseError || isString(e))
return getFormFeedbackForError(e)
return getFormFeedbackForError('general')
}
redirect('/boards')
}
60 changes: 0 additions & 60 deletions next-tavla/app/(admin)/boards/utils/formActions.ts

This file was deleted.

34 changes: 22 additions & 12 deletions next-tavla/app/(admin)/boards/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
function hash(seq: string) {
const first = seq.charCodeAt(0)
const last = seq.charCodeAt(seq.length - 1)
const coefficient = first << last
return seq
.split('')
.reduce((acc, curr) => acc + curr.charCodeAt(0) * coefficient, 0)
let hash = 0
for (let i = 0; i < seq.length; i++) {
const char = seq.charCodeAt(i)
hash = (hash << 5) - hash + char
}
return hash
}

export function colorsFromHash(
name: string,
saturation?: number,
lightness?: number,
) {
return `hsl(${hash(name) % 360},${saturation ?? 80}%,${lightness ?? 40}%)`
export const dataColors = {
azure: 'var(--data-visualization-azure)',
blue: 'var(--data-visualization-blue)',
coral: 'var(--data-visualization-coral)',
jungle: 'var(--data-visualization-jungle)',
lavender: 'var(--data-visualization-lavender)',
lilac: 'var(--data-visualization-lilac)',
peach: 'var(--data-visualization-peach)',
spring: 'var(--data-visualization-spring)',
}

const colorValues = Object.values(dataColors)

export function colorsFromHash(name: string) {
const index = Math.abs(hash(name)) % colorValues.length
return colorValues[index]
}

export function sortArrayByOverlap<T>(toBeSorted: T[], overlapArray: T[]): T[] {
Expand Down
39 changes: 0 additions & 39 deletions next-tavla/app/(admin)/boards/utils/updateTags.ts

This file was deleted.

8 changes: 8 additions & 0 deletions next-tavla/app/(admin)/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ export function getFormFeedbackForError(
variant: 'success',
}
}
case 'tags/name-missing': {
return {
form_type: 'general',
feedback:
'Merkelappen kan ikke være tom eller bare bestå av mellomrom.',
variant: 'error',
}
}
}

return {
Expand Down
Loading

0 comments on commit 4a0d508

Please sign in to comment.