150 lines
5.9 KiB
TypeScript
150 lines
5.9 KiB
TypeScript
import React from 'react'
|
|
import { useCheckoutAddress } from '../hooks/checkout-hooks'
|
|
import { trpc } from '../lib/trpc-client'
|
|
import { useQueryClient } from '@tanstack/react-query'
|
|
import { p, div } from 'web-components'
|
|
import { MapPin, Home, Briefcase, Check, Plus, Edit2, Trash2 } from 'lucide-react'
|
|
|
|
interface AddressSelectorProps {
|
|
onAddressSelect?: (addressId: number) => void
|
|
onAddAddress?: () => void
|
|
onEditAddress?: (address: any) => void
|
|
}
|
|
|
|
export function CheckoutAddressSelector({ onAddressSelect, onAddAddress, onEditAddress }: AddressSelectorProps) {
|
|
const {
|
|
sortedAddresses,
|
|
selectedAddressId,
|
|
handleAddressSelect,
|
|
} = useCheckoutAddress({ onAddressSelect })
|
|
|
|
const queryClient = useQueryClient()
|
|
const deleteMutation = trpc.user.address.deleteAddress.useMutation({
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['user.address.getUserAddresses'] })
|
|
},
|
|
})
|
|
|
|
const getAddressIcon = (name: string) => {
|
|
const lower = name.toLowerCase()
|
|
if (lower.includes('home')) return <Home className="h-5 w-5" />
|
|
if (lower.includes('work')) return <Briefcase className="h-5 w-5" />
|
|
return <MapPin className="h-5 w-5" />
|
|
}
|
|
|
|
return (
|
|
<div className="mb-6">
|
|
<div className="mb-4 flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-50">
|
|
<MapPin className="h-4 w-4 text-blue-500" />
|
|
</div>
|
|
<p className="font-bold text-lg text-gray-900">
|
|
Delivery Address
|
|
</p>
|
|
</div>
|
|
<div
|
|
onClick={onAddAddress}
|
|
className="flex items-center gap-1 text-brand-500"
|
|
>
|
|
<Plus className="h-4 w-4" />
|
|
<p className="font-bold text-sm">
|
|
Add New
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{sortedAddresses.length === 0 ? (
|
|
<div className="flex flex-col items-center justify-center rounded-xl border-2 border-dashed border-gray-200 bg-gray-50 p-8">
|
|
<MapPin className="mb-2 h-10 w-10 text-gray-400" />
|
|
<p className="mb-1 text-gray-500">No addresses found</p>
|
|
<div
|
|
onClick={onAddAddress}
|
|
className="mt-3 rounded-lg bg-brand-500 px-4 py-2"
|
|
>
|
|
<p className="font-bold text-sm text-white">
|
|
Add Address
|
|
</p>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-3">
|
|
{sortedAddresses.map((address: any) => (
|
|
<div
|
|
key={address.id}
|
|
onClick={() => handleAddressSelect(address.id)}
|
|
className={`relative cursor-pointer rounded-xl border-2 p-4 transition-all ${
|
|
selectedAddressId === address.id
|
|
? 'border-brand-500 bg-blue-50'
|
|
: 'border-gray-200 bg-white hover:border-gray-300'
|
|
}`}
|
|
>
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex items-start gap-3">
|
|
<div
|
|
className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-full ${
|
|
selectedAddressId === address.id ? 'bg-brand-500 text-white' : 'bg-gray-100 text-gray-500'
|
|
}`}
|
|
>
|
|
{getAddressIcon(address.name)}
|
|
</div>
|
|
<div className="min-w-0 flex-1">
|
|
<div className="mb-1 flex items-center gap-2">
|
|
<p className={`font-bold ${selectedAddressId === address.id ? 'text-brand-600' : 'text-gray-900'}`}>
|
|
{address.name}
|
|
</p>
|
|
{address.isDefault && (
|
|
<span className="rounded bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700">
|
|
Default
|
|
</span>
|
|
)}
|
|
</div>
|
|
<p className="text-sm leading-relaxed text-gray-600">
|
|
{address.addressLine1}
|
|
{address.addressLine2 ? `, ${address.addressLine2}` : ''}
|
|
</p>
|
|
<p className="text-sm text-gray-600">
|
|
{address.city}, {address.state} - {address.pincode}
|
|
</p>
|
|
<p className="mt-1 text-xs text-gray-500">
|
|
Phone: {address.phone}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col items-end gap-2">
|
|
{selectedAddressId === address.id && (
|
|
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-brand-500">
|
|
<Check className="h-4 w-4 text-white" />
|
|
</div>
|
|
)}
|
|
<div className="flex gap-1">
|
|
<div
|
|
onClick={(e) => {
|
|
e.stopPropagation()
|
|
onEditAddress?.(address)
|
|
}}
|
|
className="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 hover:bg-gray-100 hover:text-gray-600"
|
|
>
|
|
<Edit2 className="h-4 w-4" />
|
|
</div>
|
|
<div
|
|
onClick={(e) => {
|
|
e.stopPropagation()
|
|
if (confirm('Are you sure you want to delete this address?')) {
|
|
deleteMutation.mutate({ id: address.id })
|
|
}
|
|
}}
|
|
className="flex h-8 w-8 items-center justify-center rounded-full text-gray-400 hover:bg-red-50 hover:text-red-500"
|
|
>
|
|
<Trash2 className="h-4 w-4" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|