I would like to update the database using remix, conform, zod, supabase and shadcn/ui with dialog

I am new to web development and currently learning.

Here is what I would like to do

  1. display the data retrieved from supabase in a table.
  2. Place an edit button on each row, and when clicked, display a dialog with the data in that row as the initial values.
  3. edit the dialog and click the update button to update the data

I do not know how to implement 2 and 3.
In 2, I cannot get the currentCampaign in the defaultValue of useForm, and the currentCampaign seems to be changed correctly in useEffect.

In 3, my code was too dirty, so I deleted it. In fact, I tried to write a process to update when actionType === “update” in the Action function, but even the formData could not be obtained correctly.

The code is as shown here.

import { Form, useActionData, redirect } from "@remix-run/react";
import { ActionFunction } from "@remix-run/node";
import { ActionFunctionArgs} from "@remix-run/node";

import { useState, useEffect } from "react";

import { useForm, getFormProps, getInputProps} from "@conform-to/react"

import { parseWithZod, getZodConstraint } from "@conform-to/zod"

import { createClient } from '@supabase/supabase-js';

import { set, z } from 'zod';

const supabaseUrl = process.env.SUPA_BASE_URL!;
const supabaseAnonKey = process.env.SUPA_BASE_API_KEY!;
const supabase = createClient(supabaseUrl, supabaseAnonKey);

import { LoaderFunction, json } from "@remix-run/node"
import {useLoaderData} from "@remix-run/react"

import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

import {
    Table,
    TableBody,
    TableCaption,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
  } from "@/components/ui/table"

import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
    DialogClose,
    DialogFooter,
    } from "@/components/ui/dialog"
import { captureRejectionSymbol } from "events";

const schema = z.object({
    career: z.preprocess(
        (val) => (val === ''? undefined : val),
        z.string({required_error: 'Career is required'}),
        ),
    shop_name: z.preprocess(
        (val) => (val === ''? undefined : val),
        z.string({required_error: 'Shop name is required'}),
    ),
    details: z.preprocess(
        (val) => (val === ''? undefined : val),
        z.string({required_error: 'Details is required'}),
    ),
    cb: z.preprocess(
        (val) => (val === ''? undefined : val),
        z.number({required_error: 'CB is required'}),
    ),
})



//Action Function
export const action: ActionFunction = async ({request}) => {
    const formData = await request.formData();
    const actionType = formData.get('_action');
    const id = formData.get('id');
    const career = formData.get('career');
    const shop_name = formData.get('shop_name');
    const details = formData.get('details');
    const cb = parseFloat(formData.get('cb') as string);

    if(actionType === 'edit'){
        console.log('edit mode');
        if(typeof id === 'string'){
            const {data, error} = await supabase
                .from('campaigns')
                .select('*')
                .eq('id', id)
                .single();

            if(error) throw new Error(error.message);
            data.mode = 'edit';
            console.log(data);
            return json(data);
        }
        
    }

    if(actionType === 'update'){
        console.log('update mode');
        console.log(formData);
        const submission = parseWithZod(formData, {schema});
        console.log(career, shop_name, details, cb);

        return 
    }

};

//Loader Function
export const loader: LoaderFunction = async () => {
    const { data, error } = await supabase
        .from('campaigns')
        .select('*');
    if (error) throw new Error(error.message);
    return json(data);
};

//Component
export default function Campaigns() {
    const data = useLoaderData();
    const result = useActionData();

    const [editDialogOpen, setEditDialogOpen] = useState(false);
    const [currentCampaign, setCurrentCampaign] = useState({});

    useEffect(() => {
        if(!result) return;

        if(result.mode === 'edit'){
            console.log('edit mode');
            console.log('result', result);
            setCurrentCampaign({...result});
        }
    }, [result]);

    useEffect(() => {
        console.log('currentCampaign', currentCampaign);
    }, [currentCampaign]);

    const [form, fields ] = useForm({
        defaultValue: {
            career: currentCampaign?.career || 'default career',
            shop_name: currentCampaign?.shop_name || 'default shop',
            details: currentCampaign?.details || 'default details',
            cb: currentCampaign?.CB || 1000,
        },
        constraint: getZodConstraint(schema),
        onValidate({formData}){
            return parseWithZod(formData,{schema});
        },
    });

    return (
      <div>
          <Table>
            <TableHeader>
                <TableRow>
                <TableHead className="w-[100px]">Operation</TableHead>
                <TableHead className="w-[100px]">Career</TableHead>
                <TableHead>Shop_name</TableHead>
                <TableHead>Details</TableHead>
                <TableHead className="text-right">CB</TableHead>
                </TableRow>
            </TableHeader>
            <TableBody>
                {data.map((campaign: any) => (
                <TableRow key={campaign.id}>
                <TableCell className="font-medium">
                    <Dialog open={editDialogOpen} onOpenChange={setEditDialogOpen}>
                        <DialogTrigger asChild>
                            <Form method="post">
                                <input type="hidden" name="id" value={campaign.id} />
                                <Button variant="outline" 
                                type="submit" 
                                value="edit" 
                                name="_action"
                                    >Edit</Button>
                            </Form>
                        </DialogTrigger>
                        <DialogContent>
                            <DialogHeader>
                                <DialogTitle>Edit campaign</DialogTitle>
                            </DialogHeader>
                                <Form method="post" {...getFormProps(form)} >
                                    <input type="hidden" name="id" value={currentCampaign?.id || ''} />
                                    <Label htmlFor={fields.career.id}>Career</Label>
                                    <Input {...getInputProps(fields.career, {type:'text'})} />
                                    <Label htmlFor={fields.shop_name.id}>Shop_name</Label>
                                    <Input {...getInputProps(fields.shop_name, {type:'text'})}  />
                                    <Label htmlFor={fields.details.id}>Details</Label>
                                    <Input {...getInputProps(fields.details, {type:'text'})} />
                                    <Label htmlFor={fields.cb.id}>CB</Label>
                                    <Input {...getInputProps(fields.cb, {type:'number'})}  />
                                    <DialogFooter className="sm:justify-start">
                                        <Button type="submit" variant="destructive" name="_action" value="update">Update</Button>
                                    </DialogFooter>
                                </Form>
                            </DialogContent>
                        </Dialog>
                </TableCell>
                <TableCell className="font-medium">{campaign.career}</TableCell>
                <TableCell>{campaign.shop_name}</TableCell>
                <TableCell>{campaign.details}</TableCell>
                <TableCell className="text-right">{campaign.CB.toLocaleString()}yen</TableCell>
                </TableRow>
                ))}
            </TableBody>
            </Table>
      </div>
    );
  }