Skip to content

Commit

Permalink
feat(create): modal step to assign new board to organization (#1304)
Browse files Browse the repository at this point in the history
* feat(api): get request for organizations

* feat(api): update post request for boards to create a private board or organization board

* feat(create): add organization step to the modal

* feat(create): component with dropdown to assign board to an organization

* feat(create): clearable organizations dropdown

* chore(create): cleanup organization step
  • Loading branch information
natashatikhonova authored Nov 8, 2023
1 parent 332a1e7 commit 73fbe6f
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 27 deletions.
6 changes: 4 additions & 2 deletions next-tavla/pages/api/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ export default async function handler(
try {
switch (request.method) {
case 'POST':
const oid = JSON.parse(request.body).oid as string
const bid = await createBoard(
user.uid,
JSON.parse(request.body) as TBoard,
oid ? oid : user.uid,
JSON.parse(request.body).board as TBoard,
oid ? 'organizations' : 'users',
)
return response.status(200).json({ bid: bid })
case 'PUT':
Expand Down
11 changes: 10 additions & 1 deletion next-tavla/pages/api/organization.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { verifyUserSession } from 'Admin/utils/auth'
import { createOrganization, initializeAdminApp } from 'Admin/utils/firebase'
import {
createOrganization,
getOrganizationsWithUser,
initializeAdminApp,
} from 'Admin/utils/firebase'
import { NextApiRequest, NextApiResponse } from 'next'

initializeAdminApp()
Expand All @@ -19,6 +23,11 @@ export default async function handler(
JSON.parse(request.body).name as string,
)
return response.status(200).json({ oid: oid })
case 'GET':
const organizations = await getOrganizationsWithUser(user.uid)
return response
.status(200)
.json({ organizations: organizations })
default:
throw new Error('Method not allowed')
}
Expand Down
22 changes: 18 additions & 4 deletions next-tavla/src/Admin/scenarios/CreateBoard/components/AddStops.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { Button } from '@entur/button'
import { Button, PrimaryButton } from '@entur/button'
import { Heading3, Paragraph } from '@entur/typography'
import { StopPlaceChip } from './StopPlaceChip'
import { TBoard } from 'types/settings'
import { useCreateBoardDispatch } from '../utils/context'
import { AddTile } from 'Admin/scenarios/Edit/components/AddTile'
import { CreateBoardButton } from './CreateBoardButton'
import { TCreatePage } from 'Admin/types/createBoard'
import { useToast } from '@entur/alert'

export function AddStops({
board,
popPage,
pushPage,
}: {
board: TBoard
popPage: () => void
pushPage: (page: TCreatePage) => void
}) {
const dispatch = useCreateBoardDispatch()

const { addToast } = useToast()
const addTile = (
name: string,
placeId: string,
Expand All @@ -30,6 +33,17 @@ export function AddStops({
})
}

const nextStep = () => {
if (!board?.tiles?.length) {
return addToast({
title: 'Ingen holdeplasser er lagt til',
content: 'Vennligst legg til en holdeplass for å fortsette',
variant: 'info',
})
}
pushPage('organization')
}

return (
<div>
<Heading3>Legg til holdeplasser i Tavla </Heading3>
Expand All @@ -48,7 +62,7 @@ export function AddStops({
<Button variant="secondary" onClick={popPage}>
Tilbake
</Button>
<CreateBoardButton board={board} />
<PrimaryButton onClick={nextStep}>Neste</PrimaryButton>
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Button } from '@entur/button'
import { Heading3, Paragraph } from '@entur/typography'
import { TBoard } from 'types/settings'
import { CreateBoardButton } from './CreateBoardButton'
import { Dropdown } from '@entur/dropdown'
import { useOrganizations } from '../hooks/useOrganizations'

export function AddToOrganization({
board,
popPage,
}: {
board: TBoard
popPage: () => void
}) {
const { organizations, selectedOrganization, setSelectedOrganization } =
useOrganizations()

return (
<div className="flexColumn w-50">
<Heading3>Vil du legge tavla til i en organisasjon? </Heading3>
<Paragraph>
Hvis du ikke velger en organisasjon, vil tavla bli lagret under
din private bruker. Det er kun du som kan administrere tavla som
opprettes.
</Paragraph>
<Dropdown
items={organizations}
label="Dine organisasjoner"
selectedItem={selectedOrganization}
onChange={setSelectedOrganization}
clearable
/>
<div className="flexRow justifyBetween mt-2">
<Button variant="secondary" onClick={popPage}>
Tilbake
</Button>
<CreateBoardButton
board={board}
oid={selectedOrganization?.value}
/>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { PrimaryButton } from '@entur/button'
import { TBoard } from 'types/settings'
import { TBoard, TOrganizationID } from 'types/settings'
import { useToast } from '@entur/alert'
import { createBoardRequest } from '../utils/create'
import router from 'next/router'

function CreateBoardButton({ board }: { board: TBoard }) {
function CreateBoardButton({
board,
oid,
}: {
board: TBoard
oid?: TOrganizationID
}) {
const { addToast } = useToast()
const handleCreateBoard = async () => {
if (!board?.tiles?.length) {
return addToast({
title: 'Ingen holdeplasser er lagt til',
content: 'Vennligst legg til holdeplasser',
variant: 'info',
})
}
try {
const response = await createBoardRequest(
board?.tiles ?? [],
board?.meta?.title ?? '',
oid,
)
await router.push(`/edit/${response.bid}`)
router.reload()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NormalizedDropdownItemType } from '@entur/dropdown'
import { getOrganizationsForUserRequest } from 'Admin/utils/fetch'
import { useCallback, useEffect, useState } from 'react'

function useOrganizations() {
const [organizationList, setOrganizationList] = useState<
NormalizedDropdownItemType[]
>([])
const [selectedOrganization, setSelectedOrganization] =
useState<NormalizedDropdownItemType | null>(null)

useEffect(() => {
getOrganizationsForUserRequest().then((res) => setOrganizationList(res))
}, [])

const organizations = useCallback(
() => organizationList,
[organizationList],
)

return { organizations, selectedOrganization, setSelectedOrganization }
}

export { useOrganizations }
9 changes: 7 additions & 2 deletions next-tavla/src/Admin/scenarios/CreateBoard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { AddStops } from './components/AddStops'
import { ToastProvider } from '@entur/alert'
import { Login } from '../Login'
import dynamic from 'next/dynamic'
import { AddToOrganization } from './components/AddToOrganization'

function CreateBoard({ loggedIn }: { loggedIn: boolean }) {
const [pages, setPages] = useState<TCreatePage[]>([])
Expand Down Expand Up @@ -45,7 +46,7 @@ function CreateBoard({ loggedIn }: { loggedIn: boolean }) {
className="flexColumn alignCenter textLeft"
>
<Stepper
steps={['Navn', 'Legg til holdeplasser']}
steps={['Navn', 'Legg til holdeplasser', 'Organisasjon']}
activeIndex={pages.length}
/>
<ToastProvider>
Expand Down Expand Up @@ -82,8 +83,12 @@ function CreatePage({
const lastPage = pages.slice(-1)[0]

switch (lastPage) {
case 'organization':
return <AddToOrganization board={board} popPage={popPage} />
case 'addStops':
return <AddStops popPage={popPage} board={board} />
return (
<AddStops popPage={popPage} pushPage={pushPage} board={board} />
)
default:
return <Name board={board} pushPage={pushPage} />
}
Expand Down
10 changes: 7 additions & 3 deletions next-tavla/src/Admin/scenarios/CreateBoard/utils/create.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { TBoard } from 'types/settings'
import { TBoard, TOrganizationID } from 'types/settings'
import { TTile } from 'types/tile'

export async function createBoardRequest(tiles: TTile[], name: string) {
export async function createBoardRequest(
tiles: TTile[],
name: string,
oid?: TOrganizationID,
) {
const board = {
tiles,
meta: {
Expand All @@ -11,7 +15,7 @@ export async function createBoardRequest(tiles: TTile[], name: string) {

const response = await fetch('/api/board', {
method: 'POST',
body: JSON.stringify(board),
body: JSON.stringify({ board: board, oid: oid }),
})

return response.json()
Expand Down
2 changes: 1 addition & 1 deletion next-tavla/src/Admin/types/createBoard.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type TCreatePage = 'name' | 'addStops'
export type TCreatePage = 'name' | 'addStops' | 'organization'
20 changes: 19 additions & 1 deletion next-tavla/src/Admin/utils/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NormalizedDropdownItemType } from '@entur/dropdown'
import { TavlaError } from 'Admin/types/error'
import { CLIENT_NAME, COUNTY_ENDPOINT, GEOCODER_ENDPOINT } from 'assets/env'
import { TBoardID } from 'types/settings'
import { TBoardID, TOrganization } from 'types/settings'

type TPartialGeoResponse = {
features: Array<{
Expand Down Expand Up @@ -96,3 +96,21 @@ export async function createOrganizationRequest(name: string) {
}
return response
}

export async function getOrganizationsForUserRequest(): Promise<
NormalizedDropdownItemType[]
> {
const response = await fetch('/api/organization', { method: 'GET' })
if (!response.ok) {
throw new TavlaError({
code: 'ORGANIZATION',
message: 'Could not get organizations',
})
}
return response.json().then((data) => {
return data.organizations.map((org: TOrganization) => ({
value: org.id,
label: org.name,
}))
})
}
13 changes: 9 additions & 4 deletions next-tavla/src/Admin/utils/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ export async function setLastActive(bid: TBoardID) {
.update({ 'meta.lastActive': Date.now() })
}

export async function createBoard(uid: TUserID, board: TBoard) {
export async function createBoard(
id: TUserID | TOrganizationID,
board: TBoard,
collection: 'users' | 'organizations',
) {
const createdBoard = await firestore()
.collection('boards')
.add({
Expand All @@ -127,10 +131,11 @@ export async function createBoard(uid: TUserID, board: TBoard) {
},
})
firestore()
.collection('users')
.doc(uid)
.collection(collection)
.doc(id)
.update({
owner: admin.firestore.FieldValue.arrayUnion(createdBoard.id),
[collection === 'users' ? 'owner' : 'boards']:
admin.firestore.FieldValue.arrayUnion(createdBoard.id),
})
return createdBoard.id
}
Expand Down

0 comments on commit 73fbe6f

Please sign in to comment.