Open ovenzeze opened 2 months ago
Product Requirements Approved 😯
test/runtest.py
for running the test suite:
python runtest.py
python runtest.py test_driver_form test_api_integration
Note: Each section should be reviewed and approved by the appropriate stakeholders before moving to the next stage. Use comments for discussions and updates.
The Driver Registration/Edit Form is a crucial component of our system, allowing new drivers to register and existing drivers to update their information. This form should be user-friendly, secure, and compliant with all relevant regulations.
This technical design outlines the implementation approach for the Driver Registration/Edit Form, based on the product requirements. We will use Vue 3 with Composition API, Nuxt 3 for server-side rendering, and Supabase for backend integration.
DriverForm.vue
BaseInput.vue
(reusable input component)BaseSelect.vue
(reusable select component)BaseDatePicker.vue
(reusable date picker component)AddressInput.vue
(composite component for address fields)SensitiveInput.vue
(for masked inputs like SSN and Account Number)driverStore
to handle driver-related operations<!-- 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 }" />
<SensitiveInput v-model="form.social_security_no" label="Social Security Number" name="social_security_no" :rules="{ required: true }" />
<BaseInput v-model="form.routing_number" label="Routing Number" name="routing_number" :rules="{ regex: /^\d{9}$/ }" />
<SensitiveInput v-model="form.account_number" label="Account Number" name="account_number" />
<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 }" />
<AddressInput v-model="form.address" />
<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 SensitiveInput from '@/components/SensitiveInput.vue'
import AddressInput from '@/components/AddressInput.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>
// useDriverForm.ts
import { ref } from 'vue'
import { useForm } from 'vee-validate'
import type { HaulblazeContact } from '@/types'
import { useDriverStore } from '@/stores/driver'
export function useDriverForm(initialData?: Partial<HaulblazeContact>) {
const driverStore = useDriverStore()
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 driverStore.submitDriverInfo(values)
// Handle successful submission
} catch (error) {
// Handle submission error
}
})
// Fetch options for select fields
const warehouseOptions = computed(() => driverStore.warehouseOptions)
const statusOptions = computed(() => driverStore.statusOptions)
const teamOptions = computed(() => driverStore.teamOptions)
const driverTypeOptions = computed(() => driverStore.driverTypeOptions)
return {
form,
isFormValid: computed(() => Object.keys(errors.value).length === 0),
handleSubmit: submitForm,
warehouseOptions,
statusOptions,
teamOptions,
driverTypeOptions
}
}
// stores/driver.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import type { HaulblazeContact } from '@/types'
import { submitDriverInfo } from '@/api/driver'
export const useDriverStore = defineStore('driver', () => {
const warehouseOptions = ref([])
const statusOptions = ref([])
const teamOptions = ref([])
const driverTypeOptions = ref([])
async function fetchOptions() {
// Fetch options from API
}
async function submitDriverInfo(data: HaulblazeContact) {
return await submitDriverInfo(data)
}
return {
warehouseOptions,
statusOptions,
teamOptions,
driverTypeOptions,
fetchOptions,
submitDriverInfo
}
})
// 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
}
The form should include the following fields based on the haulblaze_contact table structure:
Driver Registration/Edit Form
[Previous content remains unchanged]
Approval Status
Next Steps
PM to complete and submit product requirements for reviewOnce requirements are approved, Tech Lead to complete and submit technical design for reviewOnce technical design is approved, QA Lead to complete and submit test plan for reviewDevelopment Plan
Current Tasks
Team members can assign themselves to tasks and update their status as they progress.