From 50030df9a69a8724439182c057c381dfb7c5a50c Mon Sep 17 00:00:00 2001 From: Sonny Date: Sun, 19 May 2024 16:23:09 +0200 Subject: [PATCH] feat: add delete collection form and controller method --- app/controllers/collections_controller.ts | 23 ++++++++++ app/validators/collection.ts | 14 ++++-- inertia/components/common/form/_button.tsx | 48 +++++++++++---------- inertia/components/common/form/_input.tsx | 4 ++ inertia/components/form/form_collection.tsx | 8 ++++ inertia/components/layouts/form_layout.tsx | 6 ++- inertia/pages/collections/delete.tsx | 41 ++++++++++++++++++ inertia/pages/collections/edit.tsx | 4 +- inertia/pages/links/edit.tsx | 2 +- start/routes/collection.ts | 7 ++- 10 files changed, 128 insertions(+), 29 deletions(-) create mode 100644 inertia/pages/collections/delete.tsx diff --git a/app/controllers/collections_controller.ts b/app/controllers/collections_controller.ts index 69ec78d..27464aa 100644 --- a/app/controllers/collections_controller.ts +++ b/app/controllers/collections_controller.ts @@ -2,6 +2,7 @@ import Collection from '#models/collection'; import User from '#models/user'; import { createCollectionValidator, + deleteCollectionValidator, updateCollectionValidator, } from '#validators/collection'; import type { HttpContext } from '@adonisjs/core/http'; @@ -82,6 +83,28 @@ export default class CollectionsController { return this.redirectToCollectionId(response, params.id); } + async showDeletePage({ auth, request, inertia, response }: HttpContext) { + const collectionId = request.qs()?.collectionId; + if (!collectionId) { + return response.redirectToNamedRoute('dashboard'); + } + + const collection = await this.getCollectionById( + collectionId, + auth.user!.id + ); + return inertia.render('collections/delete', { + collection, + }); + } + + async delete({ request, auth, response }: HttpContext) { + const { params } = await request.validateUsing(deleteCollectionValidator); + const collection = await this.getCollectionById(params.id, auth.user!.id); + await collection.delete(); + return response.redirectToNamedRoute('dashboard'); + } + /** * Get collection by id. * diff --git a/app/validators/collection.ts b/app/validators/collection.ts index 2ce8389..3e16626 100644 --- a/app/validators/collection.ts +++ b/app/validators/collection.ts @@ -1,6 +1,10 @@ import vine, { SimpleMessagesProvider } from '@vinejs/vine'; import { Visibility } from '../enums/visibility.js'; +const params = vine.object({ + id: vine.string().trim(), +}); + export const createCollectionValidator = vine.compile( vine.object({ name: vine.string().trim().minLength(1).maxLength(254), @@ -17,9 +21,13 @@ export const updateCollectionValidator = vine.compile( visibility: vine.enum(Visibility), nextId: vine.string().optional(), - params: vine.object({ - id: vine.string().trim(), - }), + params, + }) +); + +export const deleteCollectionValidator = vine.compile( + vine.object({ + params, }) ); diff --git a/inertia/components/common/form/_button.tsx b/inertia/components/common/form/_button.tsx index 566ab90..c42b21b 100644 --- a/inertia/components/common/form/_button.tsx +++ b/inertia/components/common/form/_button.tsx @@ -1,27 +1,31 @@ import styled from '@emotion/styled'; -const Button = styled.button(({ theme }) => ({ - cursor: 'pointer', - width: '100%', - textTransform: 'uppercase', - fontSize: '14px', - color: theme.colors.white, - background: theme.colors.primary, - padding: '0.75em', - border: `1px solid ${theme.colors.primary}`, - borderRadius: theme.border.radius, - transition: theme.transition.delay, - - '&:disabled': { - cursor: 'not-allowed', - opacity: '0.5', - }, - - '&:not(:disabled):hover': { - boxShadow: `${theme.colors.darkBlue} 0 0 3px 1px`, - background: theme.colors.darkBlue, +const Button = styled.button<{ danger?: boolean }>(({ theme, danger }) => { + const btnColor = !danger ? theme.colors.primary : theme.colors.lightRed; + const btnDarkColor = !danger ? theme.colors.darkBlue : theme.colors.lightRed; + return { + cursor: 'pointer', + width: '100%', + textTransform: 'uppercase', + fontSize: '14px', color: theme.colors.white, - }, -})); + background: btnColor, + padding: '0.75em', + border: `1px solid ${btnColor}`, + borderRadius: theme.border.radius, + transition: theme.transition.delay, + + '&:disabled': { + cursor: 'not-allowed', + opacity: '0.5', + }, + + '&:not(:disabled):hover': { + boxShadow: `${btnDarkColor} 0 0 3px 1px`, + background: btnDarkColor, + color: theme.colors.white, + }, + }; +}); export default Button; diff --git a/inertia/components/common/form/_input.tsx b/inertia/components/common/form/_input.tsx index 0479f90..eabff00 100644 --- a/inertia/components/common/form/_input.tsx +++ b/inertia/components/common/form/_input.tsx @@ -14,6 +14,10 @@ const Input = styled.input(({ theme }) => ({ borderBottom: `2px solid ${theme.colors.primary}`, }, + '&:disabled': { + opacity: 0.5, + }, + '&::placeholder': { fontStyle: 'italic', color: theme.colors.grey, diff --git a/inertia/components/form/form_collection.tsx b/inertia/components/form/form_collection.tsx index 4bfc50a..1c4661e 100644 --- a/inertia/components/form/form_collection.tsx +++ b/inertia/components/form/form_collection.tsx @@ -18,6 +18,8 @@ interface FormCollectionProps { disableHomeLink?: boolean; data: FormCollectionData; errors?: Record>; + disableInputs?: boolean; + submitBtnDanger?: boolean; setData: (name: string, value: any) => void; handleSubmit: () => void; @@ -29,6 +31,8 @@ export default function FormCollection({ disableHomeLink, data, errors, + disableInputs = false, + submitBtnDanger = false, setData, handleSubmit, @@ -48,6 +52,7 @@ export default function FormCollection({ handleSubmit={onSubmit} canSubmit={canSubmit} disableHomeLink={disableHomeLink} + submitBtnDanger={submitBtnDanger} > diff --git a/inertia/components/layouts/form_layout.tsx b/inertia/components/layouts/form_layout.tsx index e521474..91bf44c 100644 --- a/inertia/components/layouts/form_layout.tsx +++ b/inertia/components/layouts/form_layout.tsx @@ -30,16 +30,20 @@ interface FormLayoutProps { textSubmitButton?: string; disableHomeLink?: boolean; + submitBtnDanger?: boolean; collectionId?: string; } export default function FormLayout({ title, children, + canSubmit, handleSubmit, textSubmitButton = i18n.t('common:confirm'), + disableHomeLink = false, + submitBtnDanger = false, collectionId, }: FormLayoutProps) { const { t } = useTranslation('common'); @@ -50,7 +54,7 @@ export default function FormLayout({

{title}

{children} -
diff --git a/inertia/pages/collections/delete.tsx b/inertia/pages/collections/delete.tsx new file mode 100644 index 0000000..ca6649a --- /dev/null +++ b/inertia/pages/collections/delete.tsx @@ -0,0 +1,41 @@ +import type Collection from '#models/collection'; +import { useForm } from '@inertiajs/react'; +import { route } from '@izzyjs/route/client'; +import { useTranslation } from 'react-i18next'; +import FormCollection, { + FormCollectionData, +} from '~/components/form/form_collection'; + +export default function DeleteCollectionPage({ + collection, +}: { + collection: Collection; +}) { + const { t } = useTranslation('common'); + const { data, setData, submit, processing, errors } = + useForm({ + name: collection.name, + description: collection.description, + visibility: collection.visibility, + }); + + const handleSubmit = () => { + const { method, url } = route('collection.delete', { + params: { id: collection.id }, + }); + submit(method, url); + }; + + return ( + + ); +} diff --git a/inertia/pages/collections/edit.tsx b/inertia/pages/collections/edit.tsx index a2f4148..fd5e249 100644 --- a/inertia/pages/collections/edit.tsx +++ b/inertia/pages/collections/edit.tsx @@ -2,6 +2,7 @@ import type Collection from '#models/collection'; import { useForm } from '@inertiajs/react'; import { route } from '@izzyjs/route/client'; import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import FormCollection, { FormCollectionData, } from '~/components/form/form_collection'; @@ -11,6 +12,7 @@ export default function EditCollectionPage({ }: { collection: Collection; }) { + const { t } = useTranslation('common'); const { data, setData, submit, processing, errors } = useForm({ name: collection.name, @@ -35,7 +37,7 @@ export default function EditCollectionPage({ return ( 'delete').as('collection.delete-form'); + router + .get('/delete', [CollectionsController, 'showDeletePage']) + .as('collection.delete-form'); + router + .delete('/:id', [CollectionsController, 'delete']) + .as('collection.delete'); }) .prefix('/collections'); })