Skip to content

Commit

Permalink
single page policy editing
Browse files Browse the repository at this point in the history
  • Loading branch information
bwiggs committed Dec 20, 2024
1 parent 28ff322 commit edd95ab
Show file tree
Hide file tree
Showing 14 changed files with 394 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use client'

import React from 'react'
import { PageHeading } from '@repo/ui/page-heading'
import { useGetInternalPolicyDetailsByIdQuery } from '@repo/codegen/src/schema'
import React, { createContext, useState, useEffect } from 'react'
import { useGetInternalPolicyDetailsByIdQuery, useUpdateInternalPolicyMutation } from '@repo/codegen/src/schema'
import { NextPage } from 'next'
import Link from 'next/link'
import { UpdateableFields } from '@/components/pages/protected/policies/policy-sidebar'
import { PolicyPage } from '@/components/pages/protected/policies/policy-page'
import { PolicyContext } from '@/components/pages/protected/policies/context'
import { Policy } from '@/components/pages/protected/policies/context'

type PageProps = {
params: { id: string }
Expand All @@ -13,15 +14,31 @@ type PageProps = {
const Page: NextPage<PageProps> = ({ params }) => {
const [result] = useGetInternalPolicyDetailsByIdQuery({ variables: { internalPolicyId: params.id } })
const { data, fetching, error } = result
const [{ error: saveError }, updatePolicy] = useUpdateInternalPolicyMutation()

const [policy, setPolicy] = useState<Policy>({ id: '', name: '' })

useEffect(() => {
if (data?.internalPolicy) {
setPolicy(data.internalPolicy)
}
}, [data])

const onFieldChange = (field: UpdateableFields, value: string) => {
setPolicy((prev) => ({ ...prev, [field]: value }))
}

const saveField = (field: UpdateableFields, value: string) => {
updatePolicy({
updateInternalPolicyId: params.id,
input: { [field]: value },
})
}

return (
<>
<Link href={`/policies-and-procedures/policies/${params.id}/edit`} className="underline">
edit
</Link>
<PageHeading eyebrow="Policies & Procedures" heading="View Policy" />
<pre>{JSON.stringify({ fetching, error, data }, null, 2)}</pre>
</>
<PolicyContext.Provider value={{ policy, saveField, onFieldChange }}>
<PolicyPage />
</PolicyContext.Provider>
)
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use client'

import React, { useEffect, useState } from 'react'
import { useCreateInternalPolicyMutation } from '@repo/codegen/src/schema'
import { NextPage } from 'next'
import { UpdateableFields } from '@/components/pages/protected/policies/policy-sidebar'
import { PolicyPage } from '@/components/pages/protected/policies/policy-page'
import { PolicyContext } from '@/components/pages/protected/policies/context'
import { Policy } from '@/components/pages/protected/policies/context'
import { useRouter } from 'next/navigation'

const Page: NextPage = async () => {
const router = useRouter()
const [{ error }, createPolicy] = useCreateInternalPolicyMutation()

const [policy, setPolicy] = useState<Policy>({ name: 'Untitled Document' })

const onFieldChange = (field: UpdateableFields, value: string) => {
setPolicy((prev) => ({ ...prev, [field]: value }))
}

const saveField = (field: UpdateableFields, value: string) => {}

const create = async () => {
const { data } = await createPolicy({ input: policy })
if (data?.createInternalPolicy?.internalPolicy?.id) {
router.push('/policies-and-procedures/policies/' + data?.createInternalPolicy.internalPolicy?.id || '')
}
}

return (
<PolicyContext.Provider value={{ policy, saveField, onFieldChange, create }}>
<PolicyPage />
</PolicyContext.Provider>
)
}

export default Page
24 changes: 24 additions & 0 deletions apps/console/src/components/pages/protected/policies/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createContext } from 'react'
import { UpdateableFields } from '@/components/pages/protected/policies/policy-sidebar'

export type Policy = {
id?: string
name: string
status?: string | null
version?: string | null
updatedAt?: string | null
updatedBy?: string | null
description?: string | null
purposeAndScope?: string | null
background?: string | null
details?: any | null
}

type PolicyContext = {
saveField?: (field: UpdateableFields, value: string) => void
onFieldChange?: (field: UpdateableFields, value: string) => void
create?: () => void
policy?: Policy
}

export const PolicyContext = createContext<PolicyContext>({})
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const PoliciesTable = () => {
const [searchTerm, setSearchTerm] = useState('')

const handleCreateNew = () => {
router.push('/policies-and-procedures/policies/create')
router.push('/policies-and-procedures/policies/new')
}

const editPolicy = (policyId: string) => {
Expand All @@ -55,10 +55,7 @@ export const PoliciesTable = () => {
header: 'Name',
cell: ({ cell, row }) => {
return (
<Link
href={'/policies-and-procedures/policies/' + row.original.id}
className="underline"
>
<Link href={'/policies-and-procedures/policies/' + row.original.id} className="underline">
{cell.getValue() as string}
</Link>
)
Expand All @@ -71,14 +68,12 @@ export const PoliciesTable = () => {
{
accessorKey: 'updatedAt',
header: 'Updated At',
cell: ({ cell }) =>
format(new Date(cell.getValue() as string), 'dd MMM yyyy'),
cell: ({ cell }) => format(new Date(cell.getValue() as string), 'dd MMM yyyy'),
},
{
accessorKey: 'createdAt',
header: 'Created At',
cell: ({ cell }) =>
format(new Date(cell.getValue() as string), 'dd MMM yyyy'),
cell: ({ cell }) => format(new Date(cell.getValue() as string), 'dd MMM yyyy'),
},
{
accessorKey: 'id',
Expand All @@ -97,18 +92,9 @@ export const PoliciesTable = () => {
<>
<div className={searchRow()}>
<div className={searchField()}>
<Input
placeholder="search"
disabled
value={searchTerm}
onChange={handleSearch}
/>
<Input placeholder="search" disabled value={searchTerm} onChange={handleSearch} />
</div>
<Button
icon={<PlusIcon />}
iconPosition="left"
onClick={handleCreateNew}
>
<Button icon={<PlusIcon />} iconPosition="left" onClick={handleCreateNew}>
Create New
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { formatRelative } from 'date-fns'
import { InfoPanel, InfoPanelSection } from '@/components/shared/info-panel/info-panel'

type PolicyInfoBarProps = {
policy: {
status?: string | null | undefined
version?: string | null | undefined
policyType?: string | null | undefined
updatedAt?: string | null | undefined
updatedBy?: string | null | undefined
}
}

export const PolicyInfoBar: React.FC<PolicyInfoBarProps> = ({ policy }) => {
return (
<InfoPanel className="border-0 my-5">
<InfoPanelSection heading="Status">{policy.status || 'Review'}</InfoPanelSection>
<InfoPanelSection heading="Version">{policy.version || '1.0.0'}</InfoPanelSection>
<InfoPanelSection heading="Policy Type">{policy.policyType}</InfoPanelSection>
<InfoPanelSection heading="Last Updated">{policy.updatedAt && formatRelative(policy.updatedAt, new Date())} by John Adams</InfoPanelSection>
</InfoPanel>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useContext } from 'react'
import { PageHeading } from '@repo/ui/page-heading'
import { PolicyInfoBar } from '@/components/pages/protected/policies/policy-info-bar'
import { PolicySidebar } from '@/components/pages/protected/policies/policy-sidebar'
import dynamic from 'next/dynamic'
import { PolicyContext } from './context'

const PlateEditor = dynamic(() => import('@/components/shared/editor/plate'), { ssr: false })

export function PolicyPage() {
const { policy } = useContext(PolicyContext)

if (!policy) {
return
}

return (
<>
<PageHeading className="grow" eyebrow="Policies & Procedures" heading={policy.name} />

{policy?.id && <PolicyInfoBar policy={policy} />}

{/* plate editor */}
<div className="flex flex-col gap-5 w-full">
{/* Main */}
<div className="w-full">
<div>
<PlateEditor content={policy?.details?.content || []} />
</div>
</div>

{/* Sidebar */}
<PolicySidebar />
</div>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use client'

import React, { useContext, Suspense } from 'react'
import { Panel, PanelHeader } from '@repo/ui/panel'
import { Button } from '@repo/ui/button'
import { EditableTextarea } from '@repo/ui/textarea'
import { PolicyContext } from './context'

export type UpdateableFields = 'description' | 'background' | 'purposeAndScope'

export const PolicySidebar: React.FC = function () {
const { policy, onFieldChange, saveField, create } = useContext(PolicyContext)

if (!policy || !onFieldChange || !saveField) {
return
}

return (
<div className="flex flex-col gap-5 w-full">
<Panel className="p-0 border-0 gap-0">
<PanelHeader heading="Description" className="p-4 text-base" noBorder />

<div className="divide-y divide-oxford-blue-100 dark:divide-oxford-blue-900 *:px-4 *:py-2">
<div>
<h3 className="text-oxford-blue-500 text-sm mb-1">Description</h3>
<Suspense fallback="Loading">
<EditableTextarea
rows={7}
onBlur={(e) => saveField('description', e.target.value)}
onChange={(e) => onFieldChange('description', e.target.value)}
value={policy.description ?? ''}
placeholder="provide a description"
/>
</Suspense>
</div>
<div>
<h3 className="text-oxford-blue-500 text-sm mb-1">Background</h3>
<EditableTextarea
rows={7}
onBlur={(e) => saveField('background', e.target.value)}
onChange={(e) => onFieldChange('background', e.target.value)}
value={policy.background ?? ''}
placeholder="provide a background"
/>
</div>
<div>
<h3 className="text-oxford-blue-500 text-sm mb-1">Purpose and Scope</h3>
<EditableTextarea
rows={7}
onBlur={(e) => saveField('purposeAndScope', e.target.value)}
onChange={(e) => onFieldChange('purposeAndScope', e.target.value)}
value={policy.purposeAndScope ?? ''}
placeholder="provide a purpose and scope"
/>
</div>
</div>
</Panel>

<Panel className="p-0 border-0 gap-0">
<PanelHeader heading="Actions" className="p-4 text-base" noBorder />
<div className="divide-y divide-oxford-blue-100 dark:divide-oxford-blue-900 *:px-4 *:py-2">
<div className="mb-4">
{policy.id ? (
<Button variant="redOutline" size="sm" full>
Delete
</Button>
) : (
<Button variant="filled" onClick={create} size="sm" full>
Create
</Button>
)}
</div>
</div>
</Panel>
<pre>{JSON.stringify(policy, null, 2)}</pre>
</div>
)
}
Loading

0 comments on commit edd95ab

Please sign in to comment.