ecom / client /src /components /location-detector.tsx
shashwatIDR's picture
Upload 147 files
b89a86e verified
import { useState } from "react";
import { useLocation } from "@/hooks/use-location";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { MapPin, ExternalLink, Copy, Share, Loader2, AlertCircle } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
interface LocationDetectorProps {
onLocationDetected: (locationData: {
latitude: number;
longitude: number;
googleMapsUrl: string;
locationDetectedAutomatically: boolean;
}) => void;
onManualLocationSubmit: (manualData: {
street: string;
city: string;
state: string;
pinCode: string;
country: string;
locationDetectedAutomatically: false;
}) => void;
}
export const LocationDetector: React.FC<LocationDetectorProps> = ({
onLocationDetected,
onManualLocationSubmit
}) => {
const { location, error, isLoading, getLocation, copyToClipboard } = useLocation();
const { toast } = useToast();
const [showManualEntry, setShowManualEntry] = useState(false);
const [manualLocation, setManualLocation] = useState({
street: "",
city: "",
state: "",
pinCode: "",
country: ""
});
const handleGetLocation = () => {
getLocation();
};
const handleUseDetectedLocation = () => {
if (location) {
onLocationDetected({
latitude: location.latitude,
longitude: location.longitude,
googleMapsUrl: location.googleMapsUrl,
locationDetectedAutomatically: true
});
toast({
title: "Location detected!",
description: "Your location has been automatically detected and saved."
});
}
};
const handleCopyUrl = async () => {
if (location) {
try {
await copyToClipboard(location.googleMapsUrl);
toast({
title: "Link copied!",
description: "Google Maps link has been copied to your clipboard."
});
} catch (err) {
toast({
variant: "destructive",
title: "Failed to copy",
description: "Could not copy the link to clipboard."
});
}
}
};
const handleManualSubmit = () => {
if (!manualLocation.street || !manualLocation.city || !manualLocation.state ||
!manualLocation.pinCode || !manualLocation.country) {
toast({
variant: "destructive",
title: "Missing information",
description: "Please fill in all required fields."
});
return;
}
onManualLocationSubmit({
...manualLocation,
locationDetectedAutomatically: false
});
toast({
title: "Manual location saved!",
description: "Your location information has been saved."
});
};
return (
<Card className="w-full max-w-md mx-auto glass-card border-0">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<MapPin className="h-5 w-5 text-primary" />
Location Detection
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Automatic Location Detection */}
<div className="space-y-3">
<Button
onClick={handleGetLocation}
disabled={isLoading}
className="w-full"
data-testid="button-get-location"
>
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
<MapPin className="mr-2 h-4 w-4" />
{isLoading ? "Getting Location..." : "Get My Location Automatically"}
</Button>
{location && (
<div className="p-4 bg-green-50 dark:bg-green-900/20 rounded-lg space-y-3" data-testid="location-detected">
<div className="text-sm">
<p className="font-semibold text-green-700 dark:text-green-300">
Location detected successfully!
</p>
<p className="text-green-600 dark:text-green-400" data-testid="coordinates">
Latitude: {location.latitude.toFixed(6)}, Longitude: {location.longitude.toFixed(6)}
</p>
{location.accuracy && (
<p className="text-xs text-green-600 dark:text-green-400">
Accuracy: ±{Math.round(location.accuracy)} meters
</p>
)}
</div>
<div className="flex gap-2">
<Button
size="sm"
onClick={() => window.open(location.googleMapsUrl, '_blank')}
data-testid="button-open-maps"
>
<ExternalLink className="mr-1 h-3 w-3" />
Open in Maps
</Button>
<Button
size="sm"
variant="outline"
onClick={handleCopyUrl}
data-testid="button-copy-link"
>
<Copy className="mr-1 h-3 w-3" />
Copy Link
</Button>
</div>
<Button
onClick={handleUseDetectedLocation}
className="w-full"
data-testid="button-use-location"
>
Use This Location
</Button>
</div>
)}
{error && (
<div className="p-4 bg-red-50 dark:bg-red-900/20 rounded-lg" data-testid="location-error">
<div className="flex items-start gap-2">
<AlertCircle className="h-4 w-4 text-red-500 mt-0.5" />
<div className="text-sm">
<p className="font-semibold text-red-700 dark:text-red-300">
Location Detection Failed
</p>
<p className="text-red-600 dark:text-red-400">{error.message}</p>
</div>
</div>
</div>
)}
</div>
<div className="flex items-center gap-2">
<Separator className="flex-1" />
<span className="text-xs text-muted-foreground">OR</span>
<Separator className="flex-1" />
</div>
{/* Manual Entry Option */}
<div className="space-y-3">
{!showManualEntry ? (
<Button
variant="outline"
onClick={() => setShowManualEntry(true)}
className="w-full"
data-testid="button-manual-entry"
>
Enter Location Manually
</Button>
) : (
<div className="space-y-3" data-testid="manual-entry-form">
<h4 className="text-sm font-semibold">Manual Location Entry</h4>
<div className="grid grid-cols-1 gap-3">
<div>
<Label htmlFor="street">Street Address</Label>
<Input
id="street"
value={manualLocation.street}
onChange={(e) => setManualLocation(prev => ({...prev, street: e.target.value}))}
placeholder="Enter street address"
data-testid="input-street"
/>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<Label htmlFor="city">City</Label>
<Input
id="city"
value={manualLocation.city}
onChange={(e) => setManualLocation(prev => ({...prev, city: e.target.value}))}
placeholder="City"
data-testid="input-city"
/>
</div>
<div>
<Label htmlFor="state">State</Label>
<Input
id="state"
value={manualLocation.state}
onChange={(e) => setManualLocation(prev => ({...prev, state: e.target.value}))}
placeholder="State"
data-testid="input-state"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<Label htmlFor="pinCode">PIN Code</Label>
<Input
id="pinCode"
value={manualLocation.pinCode}
onChange={(e) => setManualLocation(prev => ({...prev, pinCode: e.target.value}))}
placeholder="PIN Code"
data-testid="input-pincode"
/>
</div>
<div>
<Label htmlFor="country">Country</Label>
<Input
id="country"
value={manualLocation.country}
onChange={(e) => setManualLocation(prev => ({...prev, country: e.target.value}))}
placeholder="Country"
data-testid="input-country"
/>
</div>
</div>
</div>
<div className="flex gap-2">
<Button
onClick={handleManualSubmit}
className="flex-1"
data-testid="button-submit-manual"
>
Use Manual Location
</Button>
<Button
variant="outline"
onClick={() => setShowManualEntry(false)}
data-testid="button-cancel-manual"
>
Cancel
</Button>
</div>
</div>
)}
</div>
</CardContent>
</Card>
);
};