Skip to content

Instantly share code, notes, and snippets.

@Thisisjuke
Last active September 25, 2023 08:52
Show Gist options
  • Save Thisisjuke/3c8a3b22e516dde15967859d15f2bec2 to your computer and use it in GitHub Desktop.
Save Thisisjuke/3c8a3b22e516dde15967859d15f2bec2 to your computer and use it in GitHub Desktop.
ValidationPanel : a custom Component to handle form submission or action validation using Shadcn <Sheet />
import React from 'react'
import { Button } from '@/modules/design-system/primitives/Button'
import { deleteResourceById } from '@/modules/crud/queries/resource'
import { ValidationPanel } from '@/modules/design-system/components/SidePanel/SidePanel'
export interface ResourceDeletionProps {
resource: any
refetch: () => void
}
export const ResourceDeletion = ({ resource, refetch }: ResourceDeletionProps) => {
return (
<ValidationPanel
validateButtonText={'Valider'}
trigger={
props => (
<Button
variant={'destructive'}
size={'lg'}
{...props}
>
Delete this resource
</Button>
)
}
onConfirm={() => {
deleteResourceById(resource.id).then(() => refetch())
}}
>
Valider ce mentor ?
</ValidationPanel>
)
}
import React from 'react'
import { Button } from '@/modules/design-system/primitives/Button'
import { MyResourceForm } from '@/modules/quiz/components/forms/MyResourceForm'
import { ValidationPanel } from '@/modules/design-system/components/SidePanel/SidePanel'
import { patchResourceById } from '@/modules/quiz/queries/resource'
export interface ResourceEditorProps {
resourceId: string
anotherProp: string
refetch: () => void
}
export const ResourceEditor = ({ resourceId, refetch, ...props }: ResourceEditorProps) => {
return (
<ValidationPanel
trigger={props => (
<Button {...props}>
Modify
</Button>
)}
onSubmit={(values: any) => {
patchResourceById(resourceId, values).then(() => refetch())
}}
>
<MyResourceForm
title={'Title!'}
{...props}
/>
</ValidationPanel>
)
}
import type { ButtonHTMLAttributes, ComponentType, ReactNode } from 'react'
import React, { useState } from 'react'
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/modules/design-system/primitives/Sheet'
import { Button } from '@/modules/design-system/primitives/Button'
export function isPromise(value: any): value is Promise<unknown> {
return (
!!value
&& (typeof value === 'object' || typeof value === 'function')
&& typeof value.then === 'function'
)
}
export function ensurePromise<T>(value: T | Promise<T>): Promise<T> {
return isPromise(value) ? value : Promise.resolve(value);
}
export interface SidePanelProps {
title?: ReactNode
children?: ReactNode
isOpen: boolean
setIsOpen: (arg: boolean) => void
}
export const SidePanel = ({ title, isOpen, setIsOpen, children }: SidePanelProps) => {
return (
<Sheet open={isOpen} onOpenChange={setIsOpen}>
<SheetContent>
<SheetHeader>
<SheetTitle>{title}</SheetTitle>
<SheetDescription asChild={true}>
<div className={'flex flex-col gap-y-2'}>
{children}
</div>
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
)
}
export interface ValidationPanelProps {
variant?: 'delete' | 'edit'
children?: ReactNode
trigger: ComponentType<ButtonHTMLAttributes<HTMLButtonElement>>
onConfirm?: () => void
onSubmit?: (args: unknown) => void
validateButtonText?: string
}
export const ValidationPanel = ({ children, trigger, onConfirm, onSubmit, validateButtonText, variant = 'edit' }: ValidationPanelProps) => {
const TriggerElement = trigger
const [isOpen, setIsOpen] = useState(false)
const isValid = React.isValidElement(children)
const Buttons = ({ shouldClose = true }) => (
<div className={'w-full flex items-center gap-x-4 mt-4'}>
<Button
type={'submit'}
variant={variant === 'edit' ? 'validate' : 'destructive'}
onClick={() => {
onConfirm && onConfirm()
shouldClose && setTimeout(() => setIsOpen(false), 300)
}}
>
{!validateButtonText && (variant === 'edit' ? 'Enregistrer' : 'Supprimer')}
{validateButtonText}
</Button>
<Button variant={'light'} onClick={() => setIsOpen(false)}>
Annuler
</Button>
</div>
)
const onFormSubmit = (data: Record<string, any>) => {
ensurePromise(onSubmit && onSubmit(data)).then(() => {
setIsOpen(false);
});
};
return (
<>
<SidePanel isOpen={isOpen} setIsOpen={setIsOpen}>
{isValid
? (
<>
{React.cloneElement(children, { onSubmit: onFormSubmit } as any, <Buttons shouldClose={false} />)}
</>
)
: (
<>
{children}
<Buttons />
</>
)
}
</SidePanel>
<TriggerElement onClick={() => setIsOpen(true)} />
</>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment