139 lines
4.7 KiB
JavaScript
139 lines
4.7 KiB
JavaScript
import React, { forwardRef, useEffect, useState } from 'react';
|
|
|
|
import { Autocomplete, TextField, Avatar, Stack } from '@mui/material';
|
|
import { MdMyLocation } from 'react-icons/md';
|
|
import { fetchAppLocations } from 'pages/api/api';
|
|
|
|
// Pill variant — opt-in via `pill` prop. Mirrors the design used across the
|
|
// deliveries / dispatch filter rows (rounded pill, soft tinted bg, accent
|
|
// border + focus ring, optional leading avatar icon). The default
|
|
// (`pill={false}` or omitted) renders the original outlined TextField with
|
|
// label "Select Zones" so existing callers are not affected.
|
|
const LocationAutocomplete = forwardRef(
|
|
(
|
|
{
|
|
locaName,
|
|
setAppId,
|
|
setLocoName,
|
|
setPage,
|
|
sx,
|
|
textfeildSx,
|
|
textfieldSx,
|
|
pill = false,
|
|
accentColor = '#6366f1',
|
|
icon,
|
|
placeholder = 'Select Zone',
|
|
paperComponent
|
|
},
|
|
ref
|
|
) => {
|
|
const [locations, setLocations] = useState(JSON.parse(localStorage.getItem('applocations') || '[]'));
|
|
|
|
useEffect(() => {
|
|
// Zones are derived from GET /admin/hubs (the new API has no dedicated
|
|
// zones resource) — see fetchAppLocations in pages/api/api.js.
|
|
const fetchLocations = async () => {
|
|
try {
|
|
const updatedLocations = await fetchAppLocations();
|
|
localStorage.setItem('applocations', JSON.stringify(updatedLocations));
|
|
setLocations(updatedLocations);
|
|
} catch (err) {
|
|
console.error('Error fetching locations in LocationAutocomplete:', err);
|
|
}
|
|
};
|
|
|
|
if (locations.length === 0) {
|
|
fetchLocations();
|
|
}
|
|
}, [locations.length]);
|
|
|
|
// Helpers (only used by pill variant) — match the deliveries page's
|
|
// token shorthand so the same opacity ramp is applied here.
|
|
const a = (suffix) => `${accentColor}${suffix}`;
|
|
const ring = a('26');
|
|
const soft = a('18');
|
|
|
|
const pillSx = pill
|
|
? {
|
|
cursor: 'pointer',
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: '10px',
|
|
bgcolor: '#ffffff',
|
|
fontWeight: 600,
|
|
color: '#0f172a',
|
|
paddingRight: '8px',
|
|
cursor: 'pointer',
|
|
transition: 'border-color 0.15s, box-shadow 0.15s',
|
|
'& fieldset': { borderColor: '#e2e8f0', borderWidth: 1 },
|
|
'&:hover fieldset': { borderColor: '#cbd5e1' },
|
|
'&.Mui-focused': { boxShadow: `0 0 0 3px ${ring}` },
|
|
'&.Mui-focused fieldset': { borderColor: accentColor, borderWidth: 1.5 }
|
|
},
|
|
'& .MuiAutocomplete-endAdornment .MuiSvgIcon-root': { color: '#94a3b8' }
|
|
}
|
|
: {};
|
|
|
|
const Adornment = pill && (
|
|
<Stack direction="row" alignItems="center" spacing={0.75} sx={{ pl: 0.5, mr: 0.25, flexShrink: 0 }}>
|
|
<Avatar
|
|
sx={{
|
|
width: 24,
|
|
height: 24,
|
|
bgcolor: soft,
|
|
color: accentColor,
|
|
transition: 'background-color 0.15s, color 0.15s'
|
|
}}
|
|
>
|
|
{icon || <MdMyLocation size={14} />}
|
|
</Avatar>
|
|
</Stack>
|
|
);
|
|
|
|
return (
|
|
<Autocomplete
|
|
id="location-autocomplete"
|
|
options={locations || []}
|
|
// Controlled by the caller's `locaName` string (the selected zone's
|
|
// locationname) so an external reset (e.g. setLocoName('All')) is
|
|
// reflected in the input — previously uncontrolled, so callers
|
|
// passing `locaName` had no effect and the pill silently kept
|
|
// showing the last user-picked zone.
|
|
value={locaName ? (locations || []).find((l) => l.locationname === locaName) ?? null : null}
|
|
isOptionEqualToValue={(option, value) => option?.applocationid === value?.applocationid}
|
|
getOptionLabel={(option) => option?.locationname ?? ''}
|
|
PaperComponent={paperComponent}
|
|
sx={{ ...sx }}
|
|
onChange={(event, value, reason) => {
|
|
if (reason === 'clear') {
|
|
setAppId?.(0);
|
|
setLocoName?.('');
|
|
setPage?.(0);
|
|
} else if (value) {
|
|
setAppId?.(value.applocationid);
|
|
setLocoName?.(value.locationname);
|
|
setPage?.(0);
|
|
}
|
|
}}
|
|
renderInput={(params) =>
|
|
pill ? (
|
|
<TextField
|
|
{...params}
|
|
inputRef={ref}
|
|
placeholder={placeholder}
|
|
InputProps={{
|
|
...params.InputProps,
|
|
startAdornment: Adornment
|
|
}}
|
|
sx={{ ...pillSx, ...(textfieldSx || textfeildSx || {}) }}
|
|
/>
|
|
) : (
|
|
<TextField {...params} inputRef={ref} label={'Select Zones'} sx={{ ...(textfieldSx || textfeildSx || {}) }} />
|
|
)
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
export default LocationAutocomplete;
|