|
32 | 32 |
|
33 | 33 | const clientSchema = z.object({ |
34 | 34 | name: z.string().min(1, 'Name is required'), |
35 | | - email: z.string().email('Invalid email'), |
| 35 | + email: z.string().email('Invalid email').optional().nullable().or(z.literal('')), |
36 | 36 | phone: z.string().optional(), |
37 | 37 | street: z.string().min(1, 'Street is required'), |
38 | 38 | city: z.string().min(1, 'City is required'), |
|
114 | 114 | if (search.value) { |
115 | 115 | const q = search.value.toLowerCase() |
116 | 116 | result = result.filter( |
117 | | - (v: any) => v.user.name.toLowerCase().includes(q) || v.user.email.toLowerCase().includes(q) |
| 117 | + (v: any) => v.user.name.toLowerCase().includes(q) || (v.user.email?.toLowerCase().includes(q) ?? false) |
118 | 118 | ) |
119 | 119 | } |
120 | 120 |
|
|
125 | 125 | if (!clients.value) return [] |
126 | 126 | const q = search.value.toLowerCase() |
127 | 127 | return clients.value.filter( |
128 | | - (c: any) => c.user.name.toLowerCase().includes(q) || c.user.email.toLowerCase().includes(q) |
| 128 | + (c: any) => c.user.name.toLowerCase().includes(q) || (c.user.email?.toLowerCase().includes(q) ?? false) |
129 | 129 | ) |
130 | 130 | }) |
131 | 131 |
|
132 | 132 | const filteredAdmins = computed(() => { |
133 | 133 | if (!admins.value) return [] |
134 | 134 | const q = search.value.toLowerCase() |
135 | 135 | return admins.value.filter( |
136 | | - (a: any) => a.name.toLowerCase().includes(q) || a.email.toLowerCase().includes(q) |
| 136 | + (a: any) => a.name.toLowerCase().includes(q) || (a.email?.toLowerCase().includes(q) ?? false) |
137 | 137 | ) |
138 | 138 | }) |
139 | 139 |
|
|
206 | 206 |
|
207 | 207 | const clientColumns: TableColumn<any>[] = [ |
208 | 208 | { accessorKey: 'user.name', header: 'Name' }, |
209 | | - { accessorKey: 'user.email', header: 'Email' }, |
| 209 | + { |
| 210 | + accessorKey: 'user.email', |
| 211 | + header: 'Email', |
| 212 | + cell: ({ row }) => row.original.user.email || 'N/A' |
| 213 | + }, |
210 | 214 | { |
211 | 215 | accessorKey: 'user.phone', |
212 | 216 | header: 'Phone', |
|
352 | 356 | const addr = client.homeAddress || {} |
353 | 357 | Object.assign(clientState, { |
354 | 358 | name: client.user.name, |
355 | | - email: client.user.email, |
| 359 | + email: client.user.email || '', |
356 | 360 | phone: client.user.phone || '', |
357 | 361 | street: addr.street || '', |
358 | 362 | city: addr.city || '', |
|
503 | 507 | :title="editingId ? 'Edit Volunteer' : 'Add Volunteer'" |
504 | 508 | > |
505 | 509 | <template #content> |
506 | | - <UForm |
507 | | - :schema="volunteerSchema" |
508 | | - :state="volunteerState" |
509 | | - class="space-y-4 p-4" |
510 | | - @submit="handleVolunteerSubmit" |
511 | | - > |
512 | | - <UFormField label="Name" name="name" |
513 | | - ><UInput v-model="volunteerState.name" class="w-full" |
514 | | - /></UFormField> |
515 | | - <UFormField label="Email" name="email" |
516 | | - ><UInput v-model="volunteerState.email" class="w-full" |
517 | | - /></UFormField> |
518 | | - <UFormField label="Phone" name="phone" |
519 | | - ><UInput v-model="volunteerPhoneProxy" class="w-full" |
520 | | - /></UFormField> |
521 | | - <UFormField label="Status" name="status"> |
522 | | - <USelect |
523 | | - v-model="volunteerState.status" |
524 | | - :items="['AVAILABLE', 'UNAVAILABLE']" |
525 | | - class="w-full" |
526 | | - /> |
527 | | - </UFormField> |
528 | | - <div class="flex justify-end gap-2 pt-4"> |
529 | | - <UButton |
530 | | - label="Cancel" |
531 | | - color="neutral" |
532 | | - variant="ghost" |
533 | | - @click="isVolunteerModalOpen = false" |
534 | | - /> |
535 | | - <UButton type="submit" label="Save" color="primary" /> |
536 | | - </div> |
537 | | - </UForm> |
| 510 | + <div @click.stop> |
| 511 | + <UForm |
| 512 | + :schema="volunteerSchema" |
| 513 | + :state="volunteerState" |
| 514 | + class="space-y-4 p-4" |
| 515 | + @submit="handleVolunteerSubmit" |
| 516 | + > |
| 517 | + <UFormField label="Name" name="name" |
| 518 | + ><UInput v-model="volunteerState.name" class="w-full" |
| 519 | + /></UFormField> |
| 520 | + <UFormField label="Email" name="email" |
| 521 | + ><UInput v-model="volunteerState.email" class="w-full" |
| 522 | + /></UFormField> |
| 523 | + <UFormField label="Phone" name="phone" |
| 524 | + ><UInput v-model="volunteerPhoneProxy" class="w-full" |
| 525 | + /></UFormField> |
| 526 | + <UFormField label="Status" name="status"> |
| 527 | + <USelect |
| 528 | + v-model="volunteerState.status" |
| 529 | + :items="['AVAILABLE', 'UNAVAILABLE']" |
| 530 | + class="w-full" |
| 531 | + /> |
| 532 | + </UFormField> |
| 533 | + <div class="flex justify-end gap-2 pt-4"> |
| 534 | + <UButton |
| 535 | + label="Cancel" |
| 536 | + color="neutral" |
| 537 | + variant="ghost" |
| 538 | + @click="isVolunteerModalOpen = false" |
| 539 | + /> |
| 540 | + <UButton type="submit" label="Save" color="primary" /> |
| 541 | + </div> |
| 542 | + </UForm> |
| 543 | + </div> |
538 | 544 | </template> |
539 | 545 | </UModal> |
540 | 546 |
|
541 | 547 | <!-- Client Modal --> |
542 | 548 | <UModal v-model:open="isClientModalOpen" :title="editingId ? 'Edit Client' : 'Add Client'"> |
543 | 549 | <template #content> |
544 | | - <UForm |
545 | | - :schema="clientSchema" |
546 | | - :state="clientState" |
547 | | - class="space-y-4 p-4" |
548 | | - @submit="handleClientSubmit" |
549 | | - > |
550 | | - <UFormField label="Name" name="name" |
551 | | - ><UInput v-model="clientState.name" class="w-full" |
552 | | - /></UFormField> |
553 | | - <UFormField label="Email" name="email" |
554 | | - ><UInput v-model="clientState.email" class="w-full" |
555 | | - /></UFormField> |
556 | | - <UFormField label="Phone" name="phone" |
557 | | - ><UInput v-model="clientPhoneProxy" class="w-full" |
558 | | - /></UFormField> |
559 | | - <UFormField label="Street" name="street" |
560 | | - ><UInput v-model="clientState.street" class="w-full" |
561 | | - /></UFormField> |
562 | | - <div class="grid grid-cols-2 gap-4"> |
563 | | - <UFormField label="City" name="city" |
564 | | - ><UInput v-model="clientState.city" class="w-full" |
| 550 | + <div @click.stop> |
| 551 | + <UForm |
| 552 | + :schema="clientSchema" |
| 553 | + :state="clientState" |
| 554 | + class="space-y-4 p-4" |
| 555 | + @submit="handleClientSubmit" |
| 556 | + > |
| 557 | + <UFormField label="Name" name="name" |
| 558 | + ><UInput v-model="clientState.name" class="w-full" |
565 | 559 | /></UFormField> |
566 | | - <UFormField label="State" name="state" |
567 | | - ><UInput v-model="clientState.state" class="w-full" |
| 560 | + <UFormField label="Email" name="email" |
| 561 | + ><UInput v-model="clientState.email" class="w-full" |
568 | 562 | /></UFormField> |
569 | | - </div> |
570 | | - <UFormField label="Zip" name="zip" |
571 | | - ><UInput v-model="clientState.zip" class="w-full" |
572 | | - /></UFormField> |
573 | | - <div class="flex justify-end gap-2 pt-4"> |
574 | | - <UButton |
575 | | - label="Cancel" |
576 | | - color="neutral" |
577 | | - variant="ghost" |
578 | | - @click="isClientModalOpen = false" |
579 | | - /> |
580 | | - <UButton type="submit" label="Save" color="primary" /> |
581 | | - </div> |
582 | | - </UForm> |
| 563 | + <UFormField label="Phone" name="phone" |
| 564 | + ><UInput v-model="clientPhoneProxy" class="w-full" |
| 565 | + /></UFormField> |
| 566 | + <UFormField label="Street" name="street" |
| 567 | + ><UInput v-model="clientState.street" class="w-full" |
| 568 | + /></UFormField> |
| 569 | + <div class="grid grid-cols-2 gap-4"> |
| 570 | + <UFormField label="City" name="city" |
| 571 | + ><UInput v-model="clientState.city" class="w-full" |
| 572 | + /></UFormField> |
| 573 | + <UFormField label="State" name="state" |
| 574 | + ><UInput v-model="clientState.state" class="w-full" |
| 575 | + /></UFormField> |
| 576 | + </div> |
| 577 | + <UFormField label="Zip" name="zip" |
| 578 | + ><UInput v-model="clientState.zip" class="w-full" |
| 579 | + /></UFormField> |
| 580 | + <div class="flex justify-end gap-2 pt-4"> |
| 581 | + <UButton |
| 582 | + label="Cancel" |
| 583 | + color="neutral" |
| 584 | + variant="ghost" |
| 585 | + @click="isClientModalOpen = false" |
| 586 | + /> |
| 587 | + <UButton type="submit" label="Save" color="primary" /> |
| 588 | + </div> |
| 589 | + </UForm> |
| 590 | + </div> |
583 | 591 | </template> |
584 | 592 | </UModal> |
585 | 593 |
|
586 | 594 | <!-- Admin Modal --> |
587 | 595 | <UModal v-model:open="isAdminModalOpen" :title="editingId ? 'Edit Admin' : 'Add Admin'"> |
588 | 596 | <template #content> |
589 | | - <UForm |
590 | | - :schema="adminSchema" |
591 | | - :state="adminState" |
592 | | - class="space-y-4 p-4" |
593 | | - @submit="handleAdminSubmit" |
594 | | - > |
595 | | - <UFormField label="Name" name="name" |
596 | | - ><UInput v-model="adminState.name" class="w-full" |
597 | | - /></UFormField> |
598 | | - <UFormField label="Email" name="email" |
599 | | - ><UInput v-model="adminState.email" class="w-full" |
600 | | - /></UFormField> |
601 | | - <UFormField label="Phone" name="phone" |
602 | | - ><UInput v-model="adminPhoneProxy" class="w-full" |
603 | | - /></UFormField> |
604 | | - <div class="flex justify-end gap-2 pt-4"> |
605 | | - <UButton |
606 | | - label="Cancel" |
607 | | - color="neutral" |
608 | | - variant="ghost" |
609 | | - @click="isAdminModalOpen = false" |
610 | | - /> |
611 | | - <UButton type="submit" label="Save" color="primary" /> |
612 | | - </div> |
613 | | - </UForm> |
| 597 | + <div @click.stop> |
| 598 | + <UForm |
| 599 | + :schema="adminSchema" |
| 600 | + :state="adminState" |
| 601 | + class="space-y-4 p-4" |
| 602 | + @submit="handleAdminSubmit" |
| 603 | + > |
| 604 | + <UFormField label="Name" name="name" |
| 605 | + ><UInput v-model="adminState.name" class="w-full" |
| 606 | + /></UFormField> |
| 607 | + <UFormField label="Email" name="email" |
| 608 | + ><UInput v-model="adminState.email" class="w-full" |
| 609 | + /></UFormField> |
| 610 | + <UFormField label="Phone" name="phone" |
| 611 | + ><UInput v-model="adminPhoneProxy" class="w-full" |
| 612 | + /></UFormField> |
| 613 | + <div class="flex justify-end gap-2 pt-4"> |
| 614 | + <UButton |
| 615 | + label="Cancel" |
| 616 | + color="neutral" |
| 617 | + variant="ghost" |
| 618 | + @click="isAdminModalOpen = false" |
| 619 | + /> |
| 620 | + <UButton type="submit" label="Save" color="primary" /> |
| 621 | + </div> |
| 622 | + </UForm> |
| 623 | + </div> |
614 | 624 | </template> |
615 | 625 | </UModal> |
616 | 626 |
|
617 | 627 | <!-- Delete Modal --> |
618 | 628 | <UModal v-model:open="isDeleteModalOpen" title="Confirm Delete"> |
619 | 629 | <template #content> |
620 | | - <div class="space-y-4 p-4"> |
| 630 | + <div class="space-y-4 p-4" @click.stop> |
621 | 631 | <p>Are you sure? This will remove the profile.</p> |
622 | 632 | <div class="flex justify-end gap-2"> |
623 | 633 | <UButton |
|
0 commit comments