feat: transition to next safe zustand

This commit is contained in:
TrèsAbhi committed 2024-07-06 20:07:46 -05:00
1 parent 595941ab9c
commit b965893bfc
9 files changed
+109 -45

No files matched your search

BIN
View File
Binary file not shown.
@@ -1,5 +1,6 @@
import { Skeleton, Table } from '@radix-ui/themes';
import { times } from 'lodash';
import { tankPerformanceSortTypeNamesArray } from '../../../../stores/tankPerformanceSort';
export function RowLoader() {
return (
@@ -8,7 +9,7 @@ export function RowLoader() {
<Skeleton height="100%" width="128px" />
</Table.RowHeaderCell>
{times(13, (index) => (
{times(tankPerformanceSortTypeNamesArray.length, (index) => (
<Table.Cell key={index} align="center">
<Skeleton height="1em" width="32px" />
</Table.Cell>
@@ -108,7 +108,7 @@ export function Tanks() {
return tanksSorted.filter((tank) =>
filterTank(filters, awaitedTankDefinitions[tank.id]),
);
}, [filters, tanksSorted]);
}, [filters, tanksSorted, sort]);
return (
<Table.Body>
+8 -5
View File
@@ -1,14 +1,17 @@
import PageWrapper from '../../../components/PageWrapper';
import { TankFiltersProvider } from '../../../stores/tankFilters';
import { FilterControl } from '../tankopedia/components/FilterControl';
import { Info } from './components/Info';
import { TankTable } from './components/Table';
export default function Page() {
return (
<PageWrapper color="jade" noMaxWidth>
<Info />
<FilterControl />
<TankTable />
</PageWrapper>
<TankFiltersProvider>
<PageWrapper color="jade" noMaxWidth>
<Info />
<FilterControl />
<TankTable />
</PageWrapper>
</TankFiltersProvider>
);
}
@@ -15,8 +15,9 @@ import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
import {
mutateTankFilters,
useTankFilters,
useTankFiltersContext,
useTankFiltersMutation,
} from '../../../../stores/tankFilters';
interface FilterControlProps {
@@ -26,6 +27,8 @@ interface FilterControlProps {
export function FilterControl({ compact }: FilterControlProps) {
const awaitedGameDefinitions = use(gameDefinitions);
const filters = useTankFilters();
const mutateTankFilters = useTankFiltersMutation();
const tankFiltersContext = useTankFiltersContext();
return (
<Flex height="fit-content" gap="2" align="start" justify="center">
@@ -321,9 +324,12 @@ export function FilterControl({ compact }: FilterControlProps) {
<Box>
<IconButton
color="red"
onClick={() =>
useTankFilters.setState(useTankFilters.getInitialState(), true)
}
onClick={() => {
tankFiltersContext.setState(
tankFiltersContext.getInitialState(),
true,
);
}}
>
<ReloadIcon />
</IconButton>
@@ -4,8 +4,8 @@ import { memo } from 'react';
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
import {
mutateTankFilters,
useTankFilters,
useTankFiltersMutation,
} from '../../../../stores/tankFilters';
import { useTankopediaSort } from '../../../../stores/tankopediaSort';
@@ -13,6 +13,7 @@ export const TierFilter = memo(() => {
const tierFilter = useTankFilters((state) => state.tiers);
const sort = useTankopediaSort();
const search = useTankFilters((state) => state.search);
const mutateTankFilters = useTankFiltersMutation();
if (sort.by !== 'meta.none' || search) return null;
@@ -25,7 +26,7 @@ export const TierFilter = memo(() => {
>
{times(10, (index) => {
const tier = (10 - index) as Tier;
const selected = tierFilter === tier;
const selected = tierFilter.includes(tier);
return (
<IconButton
@@ -36,7 +37,11 @@ export const TierFilter = memo(() => {
highContrast
onClick={() =>
mutateTankFilters((draft) => {
draft.tiers = tier;
if (draft.tiers?.includes(tier)) {
draft.tiers = draft.tiers?.filter((t) => t !== tier);
} else {
draft.tiers = [...(draft.tiers ?? []), tier];
}
})
}
>
+7 -4
View File
@@ -3,15 +3,18 @@
import { AdMidSectionResponsive } from '../../../components/AdMidSectionResponsive';
import PageWrapper from '../../../components/PageWrapper';
import { useAdExempt } from '../../../hooks/useAdExempt';
import { TankFiltersProvider } from '../../../stores/tankFilters';
import { TankSearch } from './components/TankSearch';
export default function Page() {
const exempt = useAdExempt();
return (
<PageWrapper color="purple" size={1028}>
<TankSearch />
{!exempt && <AdMidSectionResponsive />}
</PageWrapper>
<TankFiltersProvider>
<PageWrapper color="purple" size={1028}>
<TankSearch />
{!exempt && <AdMidSectionResponsive />}
</PageWrapper>
</TankFiltersProvider>
);
}
-27
View File
@@ -1,27 +0,0 @@
import { produce } from 'immer';
import { create } from 'zustand';
import { TankClass, TreeType } from '../components/Tanks';
import { Tier } from '../core/blitzkit/tankDefinitions';
export interface TankFilters {
tiers: Tier[];
nations: string[];
classes: TankClass[];
types: TreeType[];
testing: 'include' | 'exclude' | 'only';
search?: string;
searching: boolean;
}
export const useTankFilters = create<TankFilters>()(() => ({
testing: 'include',
searching: false,
classes: [],
nations: [],
tiers: [],
types: [],
}));
export function mutateTankFilters(recipe: (draft: TankFilters) => void) {
useTankFilters.setState(produce(recipe));
}
+73
View File
@@ -0,0 +1,73 @@
'use client';
import { produce } from 'immer';
import { createContext, ReactNode, useContext, useRef } from 'react';
import { createStore, StoreApi, useStore } from 'zustand';
import { TankClass, TreeType } from '../components/Tanks';
import { Tier } from '../core/blitzkit/tankDefinitions';
export interface TankFilters {
tiers: Tier[];
nations: string[];
classes: TankClass[];
types: TreeType[];
testing: 'include' | 'exclude' | 'only';
search?: string;
searching: boolean;
}
export const tankFiltersInitialState: TankFilters = {
testing: 'include',
searching: false,
classes: [],
nations: [],
tiers: [],
types: [],
};
const createTankFiltersStore = (
initialState: TankFilters = tankFiltersInitialState,
) => createStore<TankFilters>()(() => ({ ...initialState }));
const TankFiltersContext = createContext<StoreApi<TankFilters> | undefined>(
undefined,
);
interface TankFiltersProviderProps {
children: ReactNode;
}
export function TankFiltersProvider({ children }: TankFiltersProviderProps) {
const storeRef = useRef<StoreApi<TankFilters>>();
if (!storeRef.current) storeRef.current = createTankFiltersStore();
return (
<TankFiltersContext.Provider value={storeRef.current}>
{children}
</TankFiltersContext.Provider>
);
}
export function useTankFiltersContext() {
const context = useContext(TankFiltersContext);
if (!context) {
throw new Error('useTankFilters must be used within TankFiltersContext');
}
return context;
}
export function useTankFilters<Type = TankFilters>(
selector: (store: TankFilters) => Type = (store) => store as Type,
): Type {
const counterStoreContext = useTankFiltersContext();
return useStore(counterStoreContext, selector);
}
export function useTankFiltersMutation() {
const counterStoreContext = useTankFiltersContext();
return function (recipe: (draft: TankFilters) => void) {
counterStoreContext.setState(produce(recipe));
};
}