mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 15:31:12 -05:00
194 lines
6.1 KiB
TypeScript
194 lines
6.1 KiB
TypeScript
import { useState } from 'react';
|
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { AutocompleteSearch } from '@/components/search/AutocompleteSearch';
|
|
import { supabase } from '@/lib/supabaseClient';
|
|
import { toast } from 'sonner';
|
|
import { getErrorMessage } from '@/lib/errorHandler';
|
|
import { Calendar } from '@/components/ui/calendar';
|
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
|
import { Calendar as CalendarIcon } from 'lucide-react';
|
|
import { format } from 'date-fns';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface AddRideCreditDialogProps {
|
|
userId: string;
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
onSuccess: (newCreditId: string) => void;
|
|
}
|
|
|
|
export function AddRideCreditDialog({ userId, open, onOpenChange, onSuccess }: AddRideCreditDialogProps) {
|
|
const [selectedRideId, setSelectedRideId] = useState<string>('');
|
|
const [selectedRideName, setSelectedRideName] = useState<string>('');
|
|
const [firstRideDate, setFirstRideDate] = useState<Date | undefined>(undefined);
|
|
const [rideCount, setRideCount] = useState(1);
|
|
const [submitting, setSubmitting] = useState(false);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
if (!selectedRideId) {
|
|
toast.error('Please select a ride');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setSubmitting(true);
|
|
|
|
// Check if credit already exists
|
|
const { data: existing } = await supabase
|
|
.from('user_ride_credits')
|
|
.select('id')
|
|
.eq('user_id', userId)
|
|
.eq('ride_id', selectedRideId)
|
|
.maybeSingle();
|
|
|
|
if (existing) {
|
|
toast.error('You already have a credit for this ride');
|
|
return;
|
|
}
|
|
|
|
const { data, error } = await supabase
|
|
.from('user_ride_credits')
|
|
.insert({
|
|
user_id: userId,
|
|
ride_id: selectedRideId,
|
|
first_ride_date: firstRideDate ? format(firstRideDate, 'yyyy-MM-dd') : null,
|
|
ride_count: rideCount
|
|
})
|
|
.select('id')
|
|
.single();
|
|
|
|
if (error) throw error;
|
|
|
|
toast.success('Ride credit added!');
|
|
handleReset();
|
|
onSuccess(data.id); // Pass the new ID
|
|
onOpenChange(false);
|
|
} catch (error: unknown) {
|
|
toast.error(getErrorMessage(error));
|
|
} finally {
|
|
setSubmitting(false);
|
|
}
|
|
};
|
|
|
|
const handleReset = () => {
|
|
setSelectedRideId('');
|
|
setSelectedRideName('');
|
|
setFirstRideDate(undefined);
|
|
setRideCount(1);
|
|
};
|
|
|
|
return (
|
|
<Dialog
|
|
open={open}
|
|
onOpenChange={(newOpen) => {
|
|
if (!newOpen) {
|
|
handleReset();
|
|
}
|
|
onOpenChange(newOpen);
|
|
}}
|
|
>
|
|
<DialogContent className="max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle>Add Ride Credit</DialogTitle>
|
|
<DialogDescription>
|
|
Log a ride you've experienced
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
<div className="space-y-2">
|
|
<Label>Search for a Ride</Label>
|
|
{!selectedRideId ? (
|
|
<AutocompleteSearch
|
|
onResultSelect={(result) => {
|
|
if (result.type === 'ride') {
|
|
setSelectedRideId(result.id);
|
|
setSelectedRideName(result.title);
|
|
}
|
|
}}
|
|
types={['ride']}
|
|
placeholder="Search rides..."
|
|
className="w-full"
|
|
/>
|
|
) : (
|
|
<div className="flex items-center justify-between p-3 border rounded-lg bg-muted/50">
|
|
<div>
|
|
<p className="font-medium">{selectedRideName}</p>
|
|
<p className="text-sm text-muted-foreground">Selected ride</p>
|
|
</div>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => {
|
|
setSelectedRideId('');
|
|
setSelectedRideName('');
|
|
}}
|
|
>
|
|
Change
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label>First Ride Date (Optional)</Label>
|
|
<Popover>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
className={cn(
|
|
'w-full justify-start text-left font-normal',
|
|
!firstRideDate && 'text-muted-foreground'
|
|
)}
|
|
>
|
|
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
{firstRideDate ? format(firstRideDate, 'PPP') : 'Pick a date'}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-auto p-0" align="start">
|
|
<Calendar
|
|
mode="single"
|
|
selected={firstRideDate}
|
|
onSelect={setFirstRideDate}
|
|
initialFocus
|
|
disabled={(date) => date > new Date()}
|
|
/>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="ride-count">Number of Rides</Label>
|
|
<Input
|
|
id="ride-count"
|
|
type="number"
|
|
min="1"
|
|
value={rideCount}
|
|
onChange={(e) => setRideCount(parseInt(e.target.value) || 1)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex gap-2 justify-end">
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={() => onOpenChange(false)}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" loading={submitting} loadingText="Adding..." disabled={!selectedRideId}>
|
|
Add Credit
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|