This commit is contained in:
@@ -2,16 +2,11 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import type { Address, UserProfile } from '../types';
|
||||
import { useApi } from './useApi';
|
||||
import * as apiClient from '../services/apiClient';
|
||||
import { useUserAddressQuery } from './queries/useUserAddressQuery';
|
||||
import { useGeocodeMutation } from './mutations/useGeocodeMutation';
|
||||
import { logger } from '../services/logger.client';
|
||||
import { useDebounce } from './useDebounce';
|
||||
|
||||
const geocodeWrapper = (address: string, signal?: AbortSignal) =>
|
||||
apiClient.geocodeAddress(address, { signal });
|
||||
const fetchAddressWrapper = (id: number, signal?: AbortSignal) =>
|
||||
apiClient.getUserAddress(id, { signal });
|
||||
|
||||
/**
|
||||
* Helper to generate a consistent address string for geocoding.
|
||||
*/
|
||||
@@ -30,6 +25,9 @@ const getAddressString = (address: Partial<Address>): string => {
|
||||
/**
|
||||
* A custom hook to manage a user's profile address, including fetching,
|
||||
* updating, and automatic/manual geocoding.
|
||||
*
|
||||
* Refactored to use TanStack Query (ADR-0005 Phase 7).
|
||||
*
|
||||
* @param userProfile The user's profile object.
|
||||
* @param isOpen Whether the parent component (e.g., a modal) is open. This is used to reset state.
|
||||
* @returns An object with address state and handler functions.
|
||||
@@ -38,47 +36,36 @@ export const useProfileAddress = (userProfile: UserProfile | null, isOpen: boole
|
||||
const [address, setAddress] = useState<Partial<Address>>({});
|
||||
const [initialAddress, setInitialAddress] = useState<Partial<Address>>({});
|
||||
|
||||
const { execute: geocode, loading: isGeocoding } = useApi<{ lat: number; lng: number }, [string]>(
|
||||
geocodeWrapper,
|
||||
// TanStack Query for fetching the address
|
||||
const { data: fetchedAddress, isLoading: isFetchingAddress } = useUserAddressQuery(
|
||||
userProfile?.address_id,
|
||||
isOpen && !!userProfile?.address_id,
|
||||
);
|
||||
const { execute: fetchAddress } = useApi<Address, [number]>(fetchAddressWrapper);
|
||||
|
||||
// Effect to fetch or reset address based on profile and modal state
|
||||
// TanStack Query mutation for geocoding
|
||||
const geocodeMutation = useGeocodeMutation();
|
||||
|
||||
// Effect to sync fetched address to local state
|
||||
useEffect(() => {
|
||||
const loadAddress = async () => {
|
||||
if (userProfile?.address_id) {
|
||||
logger.debug(
|
||||
`[useProfileAddress] Profile has address_id: ${userProfile.address_id}. Fetching.`,
|
||||
);
|
||||
const fetchedAddress = await fetchAddress(userProfile.address_id);
|
||||
if (fetchedAddress) {
|
||||
logger.debug('[useProfileAddress] Successfully fetched address:', fetchedAddress);
|
||||
setAddress(fetchedAddress);
|
||||
setInitialAddress(fetchedAddress);
|
||||
} else {
|
||||
logger.warn(
|
||||
`[useProfileAddress] Fetch returned null for addressId: ${userProfile.address_id}.`,
|
||||
);
|
||||
setAddress({});
|
||||
setInitialAddress({});
|
||||
}
|
||||
} else {
|
||||
logger.debug('[useProfileAddress] Profile has no address_id. Resetting address form.');
|
||||
setAddress({});
|
||||
setInitialAddress({});
|
||||
}
|
||||
};
|
||||
|
||||
if (isOpen && userProfile) {
|
||||
loadAddress();
|
||||
} else {
|
||||
if (!isOpen || !userProfile) {
|
||||
logger.debug(
|
||||
'[useProfileAddress] Modal is closed or profile is null. Resetting address state.',
|
||||
);
|
||||
setAddress({});
|
||||
setInitialAddress({});
|
||||
return;
|
||||
}
|
||||
}, [isOpen, userProfile, fetchAddress]); // fetchAddress is stable from useApi
|
||||
|
||||
if (fetchedAddress) {
|
||||
logger.debug('[useProfileAddress] Successfully fetched address:', fetchedAddress);
|
||||
setAddress(fetchedAddress);
|
||||
setInitialAddress(fetchedAddress);
|
||||
} else if (!userProfile.address_id) {
|
||||
logger.debug('[useProfileAddress] Profile has no address_id. Resetting address form.');
|
||||
setAddress({});
|
||||
setInitialAddress({});
|
||||
}
|
||||
}, [isOpen, userProfile, fetchedAddress]);
|
||||
|
||||
const handleAddressChange = useCallback((field: keyof Address, value: string) => {
|
||||
setAddress((prev) => ({ ...prev, [field]: value }));
|
||||
@@ -93,13 +80,18 @@ export const useProfileAddress = (userProfile: UserProfile | null, isOpen: boole
|
||||
}
|
||||
|
||||
logger.debug(`[useProfileAddress] Manual geocode triggering for: ${addressString}`);
|
||||
const result = await geocode(addressString);
|
||||
if (result) {
|
||||
const { lat, lng } = result;
|
||||
setAddress((prev) => ({ ...prev, latitude: lat, longitude: lng }));
|
||||
toast.success('Address re-geocoded successfully!');
|
||||
try {
|
||||
const result = await geocodeMutation.mutateAsync(addressString);
|
||||
if (result) {
|
||||
const { lat, lng } = result;
|
||||
setAddress((prev) => ({ ...prev, latitude: lat, longitude: lng }));
|
||||
toast.success('Address re-geocoded successfully!');
|
||||
}
|
||||
} catch (error) {
|
||||
// Error is already logged by the mutation, but we could show a toast here if needed
|
||||
logger.error('[useProfileAddress] Manual geocode failed:', error);
|
||||
}
|
||||
}, [address, geocode]);
|
||||
}, [address, geocodeMutation]);
|
||||
|
||||
// --- Automatic Geocoding Logic ---
|
||||
const debouncedAddress = useDebounce(address, 1500);
|
||||
@@ -127,22 +119,28 @@ export const useProfileAddress = (userProfile: UserProfile | null, isOpen: boole
|
||||
}
|
||||
|
||||
logger.debug(`[useProfileAddress] Auto-geocoding: "${addressString}"`);
|
||||
const result = await geocode(addressString);
|
||||
if (result) {
|
||||
logger.debug('[useProfileAddress] Auto-geocode API returned result:', result);
|
||||
const { lat, lng } = result;
|
||||
setAddress((prev) => ({ ...prev, latitude: lat, longitude: lng }));
|
||||
toast.success('Address geocoded successfully!');
|
||||
try {
|
||||
const result = await geocodeMutation.mutateAsync(addressString);
|
||||
if (result) {
|
||||
logger.debug('[useProfileAddress] Auto-geocode API returned result:', result);
|
||||
const { lat, lng } = result;
|
||||
setAddress((prev) => ({ ...prev, latitude: lat, longitude: lng }));
|
||||
toast.success('Address geocoded successfully!');
|
||||
}
|
||||
} catch (error) {
|
||||
// Error handling - auto-geocode failures are logged but don't block the user
|
||||
logger.warn('[useProfileAddress] Auto-geocode failed:', error);
|
||||
}
|
||||
};
|
||||
|
||||
handleAutoGeocode();
|
||||
}, [debouncedAddress, initialAddress, geocode]);
|
||||
}, [debouncedAddress, initialAddress, geocodeMutation]);
|
||||
|
||||
return {
|
||||
address,
|
||||
initialAddress,
|
||||
isGeocoding,
|
||||
isGeocoding: geocodeMutation.isPending,
|
||||
isFetchingAddress,
|
||||
handleAddressChange,
|
||||
handleManualGeocode,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user