grocery-app/frontend/src/components/store/StoreTabs.jsx
2026-06-02 01:02:25 -07:00

198 lines
6.4 KiB
JavaScript

import { useContext, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { StoreContext } from '../../context/StoreContext';
import '../../styles/components/StoreTabs.css';
const DEFAULT_LOCATION_NAME = "Default Location";
function getStoreKey(store) {
return String(store?.household_store_id ?? store?.store_id ?? store?.id ?? "");
}
function getStoreName(store) {
return store?.name || store?.display_name || "Store";
}
function getLocationName(store) {
if (!store) return "Location";
const locationName = store.location_name || "";
if (!locationName || locationName === DEFAULT_LOCATION_NAME) {
return "Default";
}
return locationName;
}
function chooseStoreLocation(locations) {
if (!locations || locations.length === 0) return null;
return (
locations.find((store) => store.location_name === "Default Location" || store.display_name === store.name) ||
locations.find((store) => store.is_default) ||
locations[0]
);
}
function buildStoreOptions(stores) {
const grouped = new Map();
for (const store of stores) {
const key = getStoreKey(store);
if (!grouped.has(key)) {
grouped.set(key, {
key,
name: getStoreName(store),
locations: [],
});
}
grouped.get(key).locations.push(store);
}
return Array.from(grouped.values()).map((group) => ({
...group,
store: chooseStoreLocation(group.locations),
}));
}
export default function StoreTabs() {
const { stores, activeStore, setActiveStore, loading } = useContext(StoreContext);
const navigate = useNavigate();
const [activePicker, setActivePicker] = useState(null);
const storeOptions = useMemo(() => buildStoreOptions(stores || []), [stores]);
const activeStoreKey = getStoreKey(activeStore);
const selectedStoreOption =
storeOptions.find((option) => option.key === activeStoreKey) || storeOptions[0];
const selectedLocations = selectedStoreOption?.locations || [];
const selectedLocation =
selectedLocations.find((location) => String(location.id) === String(activeStore?.id)) ||
selectedStoreOption?.store;
const canPickStore = storeOptions.length > 1 && !loading;
const canPickLocation = selectedLocations.length > 1 && !loading;
if (!stores || stores.length === 0 || storeOptions.length === 0) {
return (
<div className="store-tabs">
<div className="store-tabs-empty">
No stores available for this household
</div>
</div>
);
}
const handleStoreTriggerClick = () => {
if (!canPickStore) return;
setActivePicker("store");
};
const handleLocationTriggerClick = () => {
if (!canPickLocation) return;
setActivePicker("location");
};
const handleStoreSelect = (store) => {
setActiveStore(store);
setActivePicker(null);
};
const handleLocationSelect = (location) => {
setActiveStore(location);
setActivePicker(null);
};
const handleManageMap = () => {
const locationQuery = selectedLocation?.id ? `&locationId=${selectedLocation.id}` : "";
navigate(`/manage?tab=stores${locationQuery}`);
};
return (
<div className="store-tabs">
<div className="store-tabs-container">
<button
type="button"
className={`store-selector-trigger ${canPickStore ? "is-interactive" : ""}`}
onClick={handleStoreTriggerClick}
disabled={loading}
aria-haspopup={canPickStore ? "dialog" : undefined}
aria-expanded={canPickStore ? activePicker === "store" : undefined}
aria-label={`Store: ${selectedStoreOption.name}`}
>
<span className="store-name">{selectedStoreOption.name}</span>
{canPickStore ? <span className="store-selector-caret" aria-hidden="true" /> : null}
</button>
<button
type="button"
className={`store-selector-trigger location-selector-trigger ${canPickLocation ? "is-interactive" : ""}`}
onClick={handleLocationTriggerClick}
disabled={loading}
aria-haspopup={canPickLocation ? "dialog" : undefined}
aria-expanded={canPickLocation ? activePicker === "location" : undefined}
aria-label={`Location: ${getLocationName(selectedLocation)}`}
>
<span className="store-name">{getLocationName(selectedLocation)}</span>
{canPickLocation ? <span className="store-selector-caret" aria-hidden="true" /> : null}
</button>
<button
type="button"
className="store-map-button"
onClick={handleManageMap}
disabled={loading || !selectedLocation}
>
Manage Map
</button>
</div>
{activePicker === "store" ? (
<div className="store-selector-modal-overlay" onClick={() => setActivePicker(null)}>
<div
className="store-selector-modal"
role="dialog"
aria-modal="true"
aria-label="Select store"
onClick={(event) => event.stopPropagation()}
>
<h2>Stores</h2>
<div className="store-selector-list">
{storeOptions.map((option) => (
<button
key={option.key}
type="button"
className={`store-selector-option ${option.key === selectedStoreOption.key ? "active" : ""}`}
onClick={() => handleStoreSelect(option.store)}
>
{option.name}
</button>
))}
</div>
</div>
</div>
) : null}
{activePicker === "location" ? (
<div className="store-selector-modal-overlay" onClick={() => setActivePicker(null)}>
<div
className="store-selector-modal"
role="dialog"
aria-modal="true"
aria-label="Select location"
onClick={(event) => event.stopPropagation()}
>
<h2>Locations</h2>
<div className="store-selector-list">
{selectedLocations.map((location) => (
<button
key={location.id}
type="button"
className={`store-selector-option ${String(location.id) === String(selectedLocation?.id) ? "active" : ""}`}
onClick={() => handleLocationSelect(location)}
>
{getLocationName(location)}
</button>
))}
</div>
</div>
</div>
) : null}
</div>
);
}