ServiceForm.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. "use client";
  2. import { useState } from "react";
  3. import { useRouter } from "next/navigation";
  4. import { Button } from "@/components/ui/button";
  5. import { Input } from "@/components/ui/input";
  6. import { DateInput } from "@/components/ui/date-input";
  7. import { Label } from "@/components/ui/label";
  8. import { Textarea } from "@/components/ui/textarea";
  9. import {
  10. Select,
  11. SelectContent,
  12. SelectItem,
  13. SelectTrigger,
  14. SelectValue,
  15. } from "@/components/ui/select";
  16. import {
  17. Dialog,
  18. DialogContent,
  19. DialogHeader,
  20. DialogTitle,
  21. } from "@/components/ui/dialog";
  22. import { useGlassModal } from "@/components/glass-modal";
  23. import { createServiceRecord } from "../Actions/serviceActions";
  24. import { Loader2 } from "lucide-react";
  25. interface ServiceFormProps {
  26. vehicleId: string;
  27. open: boolean;
  28. onOpenChange: (open: boolean) => void;
  29. }
  30. export function ServiceForm({
  31. vehicleId,
  32. open,
  33. onOpenChange,
  34. }: ServiceFormProps) {
  35. const router = useRouter();
  36. const modal = useGlassModal();
  37. const [loading, setLoading] = useState(false);
  38. const [type, setType] = useState("maintenance");
  39. const [serviceDate, setServiceDate] = useState(new Date().toISOString().split("T")[0]);
  40. const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
  41. e.preventDefault();
  42. setLoading(true);
  43. const formData = new FormData(e.currentTarget);
  44. const result = await createServiceRecord({
  45. vehicleId,
  46. title: formData.get("title") as string,
  47. description: (formData.get("description") as string) || undefined,
  48. type,
  49. cost: Number(formData.get("cost")) || 0,
  50. mileage: Number(formData.get("mileage")) || undefined,
  51. serviceDate:
  52. (formData.get("serviceDate") as string) || new Date().toISOString(),
  53. shopName: (formData.get("shopName") as string) || undefined,
  54. techName: (formData.get("techName") as string) || undefined,
  55. parts: (formData.get("parts") as string) || undefined,
  56. laborHours: Number(formData.get("laborHours")) || undefined,
  57. });
  58. if (result.success) {
  59. onOpenChange(false);
  60. router.refresh();
  61. } else {
  62. modal.open("error", "Error", result.error || "Failed to create record");
  63. }
  64. setLoading(false);
  65. };
  66. return (
  67. <Dialog open={open} onOpenChange={onOpenChange}>
  68. <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-lg">
  69. <DialogHeader>
  70. <DialogTitle>Add Service Record</DialogTitle>
  71. </DialogHeader>
  72. <form onSubmit={handleSubmit} className="space-y-4">
  73. <div className="space-y-2">
  74. <Label htmlFor="title">Title *</Label>
  75. <Input
  76. id="title"
  77. name="title"
  78. placeholder="Oil Change"
  79. required
  80. />
  81. </div>
  82. <div className="grid grid-cols-2 gap-4">
  83. <div className="space-y-2">
  84. <Label>Type</Label>
  85. <Select value={type} onValueChange={setType}>
  86. <SelectTrigger>
  87. <SelectValue />
  88. </SelectTrigger>
  89. <SelectContent>
  90. <SelectItem value="maintenance">Maintenance</SelectItem>
  91. <SelectItem value="repair">Repair</SelectItem>
  92. <SelectItem value="upgrade">Upgrade</SelectItem>
  93. <SelectItem value="inspection">Inspection</SelectItem>
  94. </SelectContent>
  95. </Select>
  96. </div>
  97. <div className="space-y-2">
  98. <Label htmlFor="serviceDate">Date</Label>
  99. <DateInput
  100. id="serviceDate"
  101. name="serviceDate"
  102. value={serviceDate}
  103. onChange={setServiceDate}
  104. />
  105. </div>
  106. </div>
  107. <div className="grid grid-cols-2 gap-4">
  108. <div className="space-y-2">
  109. <Label htmlFor="cost">Cost ($)</Label>
  110. <Input
  111. id="cost"
  112. name="cost"
  113. type="number"
  114. step="0.01"
  115. placeholder="0.00"
  116. />
  117. </div>
  118. <div className="space-y-2">
  119. <Label htmlFor="mileage">Mileage</Label>
  120. <Input
  121. id="mileage"
  122. name="mileage"
  123. type="number"
  124. placeholder="50000"
  125. />
  126. </div>
  127. </div>
  128. <div className="grid grid-cols-2 gap-4">
  129. <div className="space-y-2">
  130. <Label htmlFor="shopName">Shop Name</Label>
  131. <Input
  132. id="shopName"
  133. name="shopName"
  134. placeholder="Joe's Auto Shop"
  135. />
  136. </div>
  137. <div className="space-y-2">
  138. <Label htmlFor="techName">Technician</Label>
  139. <Input
  140. id="techName"
  141. name="techName"
  142. placeholder="Mike"
  143. />
  144. </div>
  145. </div>
  146. <div className="space-y-2">
  147. <Label htmlFor="parts">Parts Used</Label>
  148. <Input
  149. id="parts"
  150. name="parts"
  151. placeholder="Oil filter, 5W-30 synthetic oil"
  152. />
  153. </div>
  154. <div className="space-y-2">
  155. <Label htmlFor="laborHours">Labor Hours</Label>
  156. <Input
  157. id="laborHours"
  158. name="laborHours"
  159. type="number"
  160. step="0.5"
  161. placeholder="1.0"
  162. />
  163. </div>
  164. <div className="space-y-2">
  165. <Label htmlFor="description">Notes</Label>
  166. <Textarea
  167. id="description"
  168. name="description"
  169. placeholder="Additional details..."
  170. rows={3}
  171. />
  172. </div>
  173. <div className="flex justify-end gap-3 pt-4">
  174. <Button
  175. type="button"
  176. variant="outline"
  177. onClick={() => onOpenChange(false)}
  178. >
  179. Cancel
  180. </Button>
  181. <Button type="submit" disabled={loading}>
  182. {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
  183. Add Record
  184. </Button>
  185. </div>
  186. </form>
  187. </DialogContent>
  188. </Dialog>
  189. );
  190. }