mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26:57 +00:00
Add option to create zone directly to filter select
This commit is contained in:
@@ -44,6 +44,7 @@ const ClubTable = () => {
|
||||
<div className="z-10 flex w-full flex-wrap items-center justify-between gap-3 p-3">
|
||||
<SearchBar />
|
||||
<RegionSelect
|
||||
syncTitle={t("syncWithMapOption")}
|
||||
classNameOverrides={{
|
||||
container: () => "flex flex-1",
|
||||
}}
|
||||
|
||||
@@ -103,7 +103,7 @@ const TournamentTable = () => {
|
||||
<TimeControlFilters />
|
||||
</div>
|
||||
|
||||
<RegionSelect />
|
||||
<RegionSelect syncTitle={t("syncWithMapOption")} />
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center" ref={datePickerRef}>
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
import { useAtom } from "jotai";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { SingleValue } from "react-select";
|
||||
import { IoAdd } from "react-icons/io5";
|
||||
import { GroupBase, OptionsOrGroups, SingleValue } from "react-select";
|
||||
|
||||
import { regionFilterAtom } from "@/atoms";
|
||||
import { BaseOption, Select, SelectProps } from "@/components/form/Select";
|
||||
import { useZones } from "@/hooks/useZones";
|
||||
import { Zone } from "@/server/myZones";
|
||||
import { useRouter } from "@/utils/navigation";
|
||||
|
||||
type RegionSelectProps = Omit<SelectProps, "options" | "value" | "onChange">;
|
||||
type RegionSelectProps = Omit<SelectProps, "options" | "value" | "onChange"> & {
|
||||
syncTitle: string;
|
||||
};
|
||||
|
||||
export const RegionSelect = (selectProps: RegionSelectProps) => {
|
||||
const t = useTranslations("Tournaments");
|
||||
type RegionOption = BaseOption<string, Zone | null>;
|
||||
type GroupedOption = GroupBase<RegionOption>;
|
||||
|
||||
export const RegionSelect = ({
|
||||
syncTitle,
|
||||
...selectProps
|
||||
}: RegionSelectProps) => {
|
||||
const t = useTranslations("Zones");
|
||||
const router = useRouter();
|
||||
const [regionFilter, setRegionFilter] = useAtom(regionFilterAtom);
|
||||
const { zones } = useZones();
|
||||
|
||||
const zoneFilterOptions: BaseOption<string, Zone | null>[] = [
|
||||
const zoneFilterOptions: OptionsOrGroups<RegionOption, GroupedOption> = [
|
||||
{
|
||||
value: "map",
|
||||
label: t("syncWithMapOption"),
|
||||
label: syncTitle,
|
||||
data: null,
|
||||
},
|
||||
{
|
||||
@@ -26,32 +37,71 @@ export const RegionSelect = (selectProps: RegionSelectProps) => {
|
||||
data: null,
|
||||
},
|
||||
|
||||
...zones.map((zone) => ({
|
||||
value: zone.id,
|
||||
label: zone.name,
|
||||
data: zone,
|
||||
})),
|
||||
{
|
||||
label: t("yourZonesSelectGroupHeader"),
|
||||
options: [
|
||||
...zones.map((zone) => ({
|
||||
value: zone.id,
|
||||
label: zone.name,
|
||||
data: zone,
|
||||
})),
|
||||
|
||||
{
|
||||
value: "create",
|
||||
label: t("createZoneSelectOption"),
|
||||
data: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const onChange = (option: SingleValue<BaseOption<string, Zone | null>>) => {
|
||||
const onChange = (option: SingleValue<RegionOption>) => {
|
||||
if (!option) return;
|
||||
if (option.value === "create") {
|
||||
router.push("/zones/create");
|
||||
return;
|
||||
}
|
||||
|
||||
if (option.value === "map" || option.value === "all")
|
||||
setRegionFilter(option.value);
|
||||
else setRegionFilter(option.data!);
|
||||
};
|
||||
|
||||
const formatGroupLabel = (data: GroupedOption) => (
|
||||
<div className="relative -translate-y-1/2 border-b-2 border-primary-500 text-xs font-bold uppercase text-primary-500 ">
|
||||
<div className="relative top-1/2 inline-block translate-y-1/2 bg-gray-50 pr-2 dark:bg-gray-700 ">
|
||||
{data.label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const formatOptionLabel = (option: RegionOption) => {
|
||||
if (option.value === "create")
|
||||
return (
|
||||
<div className="flex items-center gap-1 italic">
|
||||
<IoAdd />
|
||||
{option.label}
|
||||
</div>
|
||||
);
|
||||
|
||||
return option.label;
|
||||
};
|
||||
|
||||
const allOptions = zoneFilterOptions.flatMap((groupOrOption) =>
|
||||
"options" in groupOrOption ? groupOrOption.options : groupOrOption,
|
||||
);
|
||||
|
||||
return (
|
||||
<Select
|
||||
options={zoneFilterOptions}
|
||||
value={zoneFilterOptions.find((o) =>
|
||||
value={allOptions.find((o) =>
|
||||
regionFilter === "all" || regionFilter === "map"
|
||||
? o.value === regionFilter
|
||||
: o.value === regionFilter.id,
|
||||
)}
|
||||
onChange={(v) =>
|
||||
onChange(v as SingleValue<BaseOption<string, Zone | null>>)
|
||||
}
|
||||
formatGroupLabel={(g) => formatGroupLabel(g as GroupedOption)}
|
||||
formatOptionLabel={(o) => formatOptionLabel(o as RegionOption)}
|
||||
onChange={(v) => onChange(v as SingleValue<RegionOption>)}
|
||||
{...selectProps}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -45,7 +45,7 @@ export const classNames = <Option, IsMulti extends boolean = false>(
|
||||
"border-gray-300 bg-gray-50 text-gray-900",
|
||||
"dark:border-gray-600 dark:bg-gray-700 dark:text-white",
|
||||
),
|
||||
groupHeading: () => "ml-3 mt-2 mb-1 text-textGray text-sm uppercase",
|
||||
groupHeading: () => "mx-3 mt-2 mb-1 text-textGray text-sm uppercase",
|
||||
option: ({ isFocused, isDisabled }) =>
|
||||
twMerge(
|
||||
"px-3 py-2 hover:cursor-pointer",
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"FormValidation": {
|
||||
"required": "Required",
|
||||
"url": "Invalid URL",
|
||||
"zone": "Please draw at least one region on the map"
|
||||
"zone": "Please draw at least one zone on the map"
|
||||
},
|
||||
|
||||
"Home": {
|
||||
@@ -81,7 +81,6 @@
|
||||
"searchLabel": "Search",
|
||||
"searchPlaceholder": "Search",
|
||||
"syncWithMapOption": "Only tournaments visible in the map view",
|
||||
"ignoreMapOption": "No region-based filter",
|
||||
"normsOnly": "Only norm tournaments",
|
||||
"noneFound": "No tournaments found",
|
||||
"date": "Date",
|
||||
@@ -98,7 +97,7 @@
|
||||
"loading": "Loading...",
|
||||
"searchLabel": "Search",
|
||||
"searchPlaceholder": "Search",
|
||||
"syncWithMapCheckbox": "Clubs visible on the map",
|
||||
"syncWithMapOption": "Only clubs visible in the map view",
|
||||
"noneFound": "No clubs found",
|
||||
"name": "Name",
|
||||
"ffe": "FFE",
|
||||
@@ -227,8 +226,12 @@
|
||||
"logonRequired": "You must be signed in to access this feature so that we can store your personalized Zones. There's no need to create an account, just sign in with your email address and we'll send you a link.",
|
||||
|
||||
"noNotifications": "You have not enabled email notifications for this zone.",
|
||||
"withNotifications": "You will receive email notifications for new tournaments with <b>{list}</b> time control in this region.",
|
||||
"addZoneButton": "Add a Region",
|
||||
"withNotifications": "You will receive email notifications for new tournaments with <b>{list}</b> time control in this zone.",
|
||||
"addZoneButton": "Add a Zone",
|
||||
|
||||
"yourZonesSelectGroupHeader": "Your Zones",
|
||||
"createZoneSelectOption": "Create a new zone",
|
||||
"ignoreMapOption": "No region-based filter",
|
||||
|
||||
"createTitle": "Create a new zone",
|
||||
"editTitle": "Edit zone",
|
||||
|
||||
@@ -80,7 +80,6 @@
|
||||
"searchLabel": "Rechercher",
|
||||
"searchPlaceholder": "Rechercher",
|
||||
"syncWithMapOption": "Seuls les tournois visibles dans la vue carte",
|
||||
"ignoreMapOption": "Pas de filtre de région",
|
||||
"normsOnly": "Uniquement tournois à normes",
|
||||
"noneFound": "Pas de tournois trouvé",
|
||||
"date": "Date",
|
||||
@@ -97,7 +96,7 @@
|
||||
"loading": "Téléchargement...",
|
||||
"searchLabel": "Rechercher",
|
||||
"searchPlaceholder": "Rechercher",
|
||||
"syncWithMapCheckbox": "Clubs visibles sur la carte",
|
||||
"syncWithMapOption": "Seuls les clubs visibles dans la vue carte",
|
||||
"noneFound": "Pas de club trouvé",
|
||||
"name": "Name",
|
||||
"ffe": "FFE",
|
||||
@@ -231,6 +230,10 @@
|
||||
"withNotifications": "Vous allez recevoir des notifications par e-mail pour les nouveaux tournois de cadences <b>{list}</b> dans cette région.",
|
||||
"addZoneButton": "Ajouter une région",
|
||||
|
||||
"yourZonesSelectGroupHeader": "Your Zones",
|
||||
"ignoreMapOption": "Pas de filtre de région",
|
||||
"createZoneSelectOption": "Create a new zone",
|
||||
|
||||
"createTitle": "Créer une nouvelle région",
|
||||
"editTitle": "Modifier région",
|
||||
|
||||
|
||||
Reference in New Issue
Block a user