Skip to content

Commit

Permalink
create new version nav icon is now dialog form with description texta…
Browse files Browse the repository at this point in the history
…rea; renamed nav combobox file; calling out multiple heads/tails on version create for next fix
  • Loading branch information
goodeats committed May 8, 2024
1 parent 234571b commit 8ccabef
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 22 deletions.
Empty file.
2 changes: 1 addition & 1 deletion app/components/templates/navbar/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './nav-actions'
export * from './combobox'
2 changes: 1 addition & 1 deletion app/models/artboard-branch/artboard-branch.get.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const getArtboardBranchWithVersions = async ({
include: {
versions: {
orderBy: {
name: 'desc',
createdAt: 'desc',
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { conform, useForm } from '@conform-to/react'
import { getFieldsetConstraint } from '@conform-to/zod'
import { useFetcher } from '@remix-run/react'
import { useEffect, useState } from 'react'
import { AuthenticityTokenInput } from 'remix-utils/csrf/react'
import { useHydrated } from 'remix-utils/use-hydrated'
import { type z } from 'zod'
import { TextareaField } from '#app/components/forms'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '#app/components/ui/dialog'
import { type IconName } from '#app/components/ui/icon'
import { PanelIconButton } from '#app/components/ui/panel-icon-button'
import { StatusButton } from '#app/components/ui/status-button'
import {
type IEntityId,
type IEntityParentId,
type entityParentIdTypeEnum,
} from '#app/schema/entity'
import { useIsPending } from '#app/utils/misc'
import { getActionType, type RoutePath } from '#app/utils/routes.utils'

// 3 things:
// friendly reminder to change the form id when switching a fetcher.form icon to dialog
// explore not needing actionData on other forms and fetcher is action, not loader
// planning to revisit design system so not as much effort to make dialog dynamic like fetcher forms

export const DialogFormVersionCreate = ({
entityId,
parentTypeId,
parentId,
route,
formId,
schema,
icon,
iconText,
title,
description,
}: {
entityId?: IEntityId
parentTypeId?: entityParentIdTypeEnum
parentId?: IEntityParentId
route: RoutePath
formId: string
schema: z.ZodSchema<any>
icon: IconName
iconText: string
title: string
description: string
}) => {
const [open, setOpen] = useState(false)

const action = getActionType(route)
const fetcher = useFetcher<typeof action>()
const isPending = useIsPending()
let isHydrated = useHydrated()
const [form, fields] = useForm({
id: `${formId}-${parentId || 'parent'}-${entityId || 'new'}`,
constraint: getFieldsetConstraint(schema),
lastSubmission: fetcher.data?.submission,
defaultValue: {
description: '',
},
})

// close dialog on successful submission
// https://www.nico.fyi/blog/close-dialog-with-use-fetcher-remix
useEffect(() => {
if (fetcher.state === 'idle' && fetcher.data?.status === 'success') {
setOpen(false)
}
}, [fetcher])

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<PanelIconButton iconName={icon} iconText={iconText} />
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<fetcher.Form method="POST" action={route} {...form.props}>
<AuthenticityTokenInput />

<input type="hidden" name="no-js" value={String(!isHydrated)} />
<input type="hidden" name="id" value={entityId} />
{parentId && (
<input type="hidden" name={parentTypeId} value={parentId} />
)}

<div className="grid grid-cols-4 items-center gap-4">
<TextareaField
labelProps={{ children: 'Description' }}
textareaProps={{
...conform.textarea(fields.description, {
ariaAttributes: true,
}),
}}
errors={fields.description.errors}
/>
</div>
</fetcher.Form>
</div>
<DialogFooter>
<StatusButton
form={form.id}
type="submit"
disabled={isPending}
status={isPending ? 'pending' : 'idle'}
>
Submit
</StatusButton>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
NavbarButtonGroup,
} from '#app/components/layout'
import { ComboboxNav } from '#app/components/templates/combobox'
import { FormFetcherIcon } from '#app/components/templates/form/fetcher/icon'
import { IconLink } from '#app/components/templates/link'
import { NewArtboardVersionSchema } from '#app/schema/artboard-version'
import { EntityParentIdType } from '#app/schema/entity'
Expand All @@ -16,6 +15,7 @@ import { artboardBranchLoaderRoute } from '../$branchSlug'
import { artboardVersionLoaderRoute } from '../$branchSlug.$versionSlug'
import { projectLoaderRoute } from '../../route'
import { artboardLoaderRoute } from '../route'
import { DialogFormVersionCreate } from './header.artboard.dialog.form.version.create'

export const ArtboardHeader = () => {
const user = useUser()
Expand Down Expand Up @@ -58,16 +58,28 @@ export const ArtboardHeader = () => {
slugParam="versionSlug"
baseUrl={`${baseUrl}/${artboard.slug}/${branch.slug}`}
/>
{!onLatestVersion && <LatestArtboardVersionLink />}
{!onLatestVersion && (
// this should be displayed when:
// - creating a new artboard version
// - navigating to a previous artboard version
<IconLink
to="../latest"
icon="pin-right"
text="Latest"
tooltipText="View the latest version of this artboard"
buttonVariant="secondary"
/>
)}
</DashboardNav>
<DashboardNav>
{/* TODO: make these have the same look as the form fetcher icon */}
<NavbarButtonGroup>
{/* <span>refresh</span> */}
{/* <span>star</span> */}
{/* <span>info a, ab, abv</span> */}
{/* <span>fork ab</span> */}
{/* <span>merge ab</span> */}
<FormFetcherIcon
<DialogFormVersionCreate
entityId={version.id}
parentId={branch.id}
parentTypeId={EntityParentIdType.ARTBOARD_BRANCH_ID}
Expand All @@ -76,8 +88,9 @@ export const ArtboardHeader = () => {
schema={NewArtboardVersionSchema}
icon="card-stack-plus"
iconText="New Version"
title="Create new version"
description="Save a new version of this artboard. Add a description to help understand the changes. Click save when you're done."
/>
{/* TODO: make this have the same look as the form fetcher icon */}
<IconLink
to={`/users/${user.username}/artboards/${artboard.slug}`}
icon="pencil-1"
Expand All @@ -90,18 +103,3 @@ export const ArtboardHeader = () => {
</DashboardHeader>
)
}

// this should be displayed when:
// - creating a new artboard version
// - navigating to a previous artboard version
const LatestArtboardVersionLink = () => {
return (
<IconLink
to="../latest"
icon="pin-right"
text="Latest"
tooltipText="View the latest version of this artboard"
buttonVariant="secondary"
/>
)
}
3 changes: 2 additions & 1 deletion app/services/artboard/branch/version/create.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const artboardVersionCreateService = async ({
branchId: artboardBranchId,
name: newName,
slug: newName,
description: 'new version -- fix me to be the description passed in',
description: description || 'new version',
width,
height,
background,
Expand All @@ -63,6 +63,7 @@ export const artboardVersionCreateService = async ({
invariant(createdArtboardVersion, 'New artboard version not created')

// Step 4: delete all artboard versions after the current artboard version
// getting multiple heads and tails on v1...
const artboardVersions = await getArtboardVersions({
where: { branchId: artboardBranchId },
})
Expand Down
2 changes: 2 additions & 0 deletions app/utils/linked-list.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ export const orderLinkedItems = <T extends ILinkedItem>(items: T[]): T[] => {
const heads = items.filter(item => !item.prevId)
if (heads.length > 1) {
console.warn('Multiple heads found in the linked list.')
console.log('heads', heads)
}

const tails = items.filter(item => !item.nextId)
if (tails.length > 1) {
console.warn('Multiple tails found in the linked list.')
console.log('tails', tails)
}

// Step 1: Find the head of the list
Expand Down

0 comments on commit 8ccabef

Please sign in to comment.