ovenzeze / nimship-admin-nuxt

https://nimship-admin-v0.vercel.app
0 stars 0 forks source link

Implement Public-Facing New Driver Registration Form #6

Open ovenzeze opened 4 weeks ago

ovenzeze commented 4 weeks ago

Driver Registration/Edit Form - Technical Design Document

Overview

This document outlines the technical design for the Driver Registration and Edit form, based on the haulblaze_contact table structure.

Component Structure

Form Fields and UI Components

Field Name UI Component Type Required Notes
first_name BaseInput text Yes
last_name BaseInput text Yes
date_of_birth BaseDatePicker date Yes
warehouse BaseSelect select Yes Options from area_code_enum_bd3e18a1
phone BaseInput tel Yes With validation
email BaseInput email No With validation
driver_license_no BaseInput text Yes
social_security_no BaseInput text Yes With masking
routing_number BaseInput text No
account_number BaseInput text No With masking
zelle BaseInput text No
enroll_time BaseDatePicker datetime No Auto-filled, editable by admin
status BaseSelect select Yes Options from status_enum_31d11e70
team_name BaseSelect select Yes Options from team_name_enum
driver_type BaseSelect select Yes Options from driver_type_enum
commisson_rate BaseInput number Yes With validation (0-100)
mail_street BaseInput text No
mail_city BaseInput text No
mail_state BaseInput text No
mail_zip BaseInput number No With validation
dl_expired_time BaseDatePicker date Yes

Component Implementation

<!-- DriverForm.vue -->
<template>
  <form @submit.prevent="handleSubmit" class="space-y-6">
    <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
      <BaseInput v-model="form.first_name" label="First Name" name="first_name" :rules="{ required: true }" />
      <BaseInput v-model="form.last_name" label="Last Name" name="last_name" :rules="{ required: true }" />
      <BaseDatePicker v-model="form.date_of_birth" label="Date of Birth" name="date_of_birth" :rules="{ required: true }" />
      <BaseSelect v-model="form.warehouse" label="Warehouse" name="warehouse" :options="warehouseOptions" :rules="{ required: true }" />
      <BaseInput v-model="form.phone" label="Phone" name="phone" type="tel" :rules="{ required: true, regex: /^\+?[1-9]\d{1,14}$/ }" />
      <BaseInput v-model="form.email" label="Email" name="email" type="email" :rules="{ email: true }" />
      <BaseInput v-model="form.driver_license_no" label="Driver's License Number" name="driver_license_no" :rules="{ required: true }" />
      <BaseInput v-model="form.social_security_no" label="Social Security Number" name="social_security_no" type="password" :rules="{ required: true }" />
      <BaseInput v-model="form.routing_number" label="Routing Number" name="routing_number" :rules="{ regex: /^\d{9}$/ }" />
      <BaseInput v-model="form.account_number" label="Account Number" name="account_number" type="password" />
      <BaseInput v-model="form.zelle" label="Zelle" name="zelle" />
      <BaseDatePicker v-model="form.enroll_time" label="Enroll Time" name="enroll_time" :disabled="!isAdmin" />
      <BaseSelect v-model="form.status" label="Status" name="status" :options="statusOptions" :rules="{ required: true }" />
      <BaseSelect v-model="form.team_name" label="Team Name" name="team_name" :options="teamOptions" :rules="{ required: true }" />
      <BaseSelect v-model="form.driver_type" label="Driver Type" name="driver_type" :options="driverTypeOptions" :rules="{ required: true }" />
      <BaseInput v-model="form.commisson_rate" label="Commission Rate" name="commisson_rate" type="number" :rules="{ required: true, min: 0, max: 100 }" />
      <BaseInput v-model="form.mail_street" label="Street Address" name="mail_street" />
      <BaseInput v-model="form.mail_city" label="City" name="mail_city" />
      <BaseInput v-model="form.mail_state" label="State" name="mail_state" />
      <BaseInput v-model="form.mail_zip" label="ZIP Code" name="mail_zip" type="number" :rules="{ regex: /^\d{5}(-\d{4})?$/ }" />
      <BaseDatePicker v-model="form.dl_expired_time" label="Driver's License Expiration Date" name="dl_expired_time" :rules="{ required: true }" />
    </div>
    <Button type="submit" :disabled="!isFormValid">{{ isEditMode ? 'Update' : 'Register' }}</Button>
  </form>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { useForm } from 'vee-validate'
import { Button } from '@/components/ui/button'
import BaseInput from '@/components/BaseInput.vue'
import BaseSelect from '@/components/BaseSelect.vue'
import BaseDatePicker from '@/components/BaseDatePicker.vue'
import { useDriverForm } from '@/composables/useDriverForm'
import type { HaulblazeContact } from '@/types'

const props = defineProps<{
  initialData?: Partial<HaulblazeContact>
  isEditMode: boolean
}>()

const { form, isFormValid, handleSubmit, warehouseOptions, statusOptions, teamOptions, driverTypeOptions } = useDriverForm(props.initialData)

const isAdmin = computed(() => {
  // Logic to determine if current user is admin
})
</script>

Composables

// useDriverForm.ts
import { ref } from 'vue'
import { useForm } from 'vee-validate'
import type { HaulblazeContact } from '@/types'
import { submitDriverInfo } from '@/api/driver'

export function useDriverForm(initialData?: Partial<HaulblazeContact>) {
  const form = ref<HaulblazeContact>({
    first_name: '',
    last_name: '',
    date_of_birth: null,
    warehouse: null,
    phone: '',
    email: null,
    driver_license_no: '',
    social_security_no: '',
    routing_number: null,
    account_number: null,
    zelle: null,
    enroll_time: new Date(),
    status: 'Onboarding',
    team_name: null,
    driver_type: 'HAULER',
    commisson_rate: 0,
    mail_street: null,
    mail_city: null,
    mail_state: null,
    mail_zip: null,
    dl_expired_time: null,
    ...initialData
  })

  const { handleSubmit, isSubmitting, errors } = useForm({
    validationSchema: {
      // Define validation schema here
    }
  })

  const submitForm = handleSubmit(async (values) => {
    try {
      await submitDriverInfo(values)
      // Handle successful submission
    } catch (error) {
      // Handle submission error
    }
  })

  // Fetch options for select fields
  const warehouseOptions = ref([])
  const statusOptions = ref([])
  const teamOptions = ref([])
  const driverTypeOptions = ref([])

  // Fetch options from API or use static data

  return {
    form,
    isFormValid: computed(() => Object.keys(errors.value).length === 0),
    handleSubmit: submitForm,
    warehouseOptions,
    statusOptions,
    teamOptions,
    driverTypeOptions
  }
}

API Integration

// api/driver.ts
import { supabase } from '@/lib/supabaseClient'
import type { HaulblazeContact } from '@/types'

export async function submitDriverInfo(data: HaulblazeContact) {
  const { data: result, error } = await supabase
    .from('haulblaze_contact')
    .upsert(data)
    .select()

  if (error) throw error
  return result
}

Types

// types/index.ts
export interface HaulblazeContact {
  id?: number
  haulblaze_id?: string
  first_name: string
  last_name: string
  date_of_birth: Date | null
  warehouse: string | null
  phone: string
  email: string | null
  driver_license_no: string
  social_security_no: string
  routing_number: string | null
  account_number: string | null
  zelle: string | null
  enroll_time: Date
  status: string
  driver_id?: number[]
  team_name: string | null
  driver_type: string
  commisson_rate: number
  mail_street: string | null
  mail_city: string | null
  mail_state: string | null
  mail_zip: number | null
  dl_expired_time: Date | null
  uid?: string
  last_update?: Date
  has_notification?: number
}

Dependencies

Security Considerations

Accessibility

Next Steps

  1. Implement BaseInput, BaseSelect, and BaseDatePicker components
  2. Create the DriverForm component
  3. Implement the useDriverForm composable
  4. Set up API integration with Supabase
  5. Add unit tests for components and composables
  6. Implement form validation logic
  7. Create admin view for editing driver information
  8. Conduct accessibility testing
  9. Perform security audit
  10. Optimize performance, especially for large datasets