Skip to content

Commit

Permalink
Refactor filter ULR implementation along with app.tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
sdg9 committed Apr 28, 2022
1 parent 6c83b58 commit 175396a
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 103 deletions.
81 changes: 26 additions & 55 deletions apps/admin-web/src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
import { RouteItemType, VariantCategory } from '@caribou-crew/mezzo-interfaces';
import React, { useState } from 'react';
import { Flipper, Flipped } from 'react-flip-toolkit';

import {
Expand All @@ -13,49 +12,31 @@ import {
import { ArrowDropDown, ArrowDropUp } from '@mui/icons-material';
import RouteItem from './components/RouteItem';
import Header from './components/Header';
import { useSort } from './utils/useSort';
import { MEZZO_API_PATH } from '@caribou-crew/mezzo-constants';
import { getFilteredRoutes } from './utils/filter';
import useFetchRoutes from './hooks/useFetchRoutes';
import useRouteFilter from './hooks/useRouteFilter';
import useRouteSort from './hooks/useRouteSort';
import useFilterFromURL, { setURLHash } from './hooks/useFilterFromURL';

type SortProperty = 'method' | 'path';
type SortProperty = 'method' | 'path' | '';
export const App = () => {
const filterPrefix = '#label';
const [routes, setRoutes] = useState<RouteItemType[]>([]);
const [version, setVersion] = useState<string>('');
const [variantCategories, setVariantCategories] = useState<VariantCategory[]>(
[]
);
const [displayedRoutes, setDisplayedRoutes] = useState<RouteItemType[]>([]);
const [selectedItem, setSelectedItem] = useState('');
const { sortBy, getSortDirection } = useSort();
const [filterValue, setFilterValue] = useState('');

useEffect(() => {
const fetchData = async () => {
const response = await fetch(`${MEZZO_API_PATH}/routes`);
const data = await response.json();
setRoutes(data.routes);
setVersion(data.appVersion);
setVariantCategories(
(data.variantCategories || []).sort(
(a: VariantCategory, b: VariantCategory) =>
(a?.order ?? 0) - (b?.order ?? 0)
)
);
const { routes, version, variantCategories } = useFetchRoutes();

const {
routes: filteredRoutes,
setFilterValue,
filterValue,
} = useRouteFilter(routes);

const hash = window.location.hash;
if (hash.length > 0) {
const value = decodeURIComponent(hash.split(`${filterPrefix}/`)?.[1]);
const filteredRoutes = getFilteredRoutes(data.routes, value);
setFilterValue(value);
setDisplayedRoutes(filteredRoutes);
} else {
setDisplayedRoutes(data.routes);
}
};
const {
routes: displayedRoutes,
setSort,
sortDirection,
sortedByProperty,
} = useRouteSort(filteredRoutes);

fetchData().catch(console.error);
}, []);
useFilterFromURL(setFilterValue);

const renderRouteList = () => {
return displayedRoutes.map((route) => (
Expand All @@ -74,8 +55,7 @@ export const App = () => {
};

const getSortIcon = (property: SortProperty) => {
const sortDirection = getSortDirection(property);
if (sortDirection != null) {
if (sortDirection != null && property === sortedByProperty) {
return sortDirection > 0 ? <ArrowDropDown /> : <ArrowDropUp />;
} else {
return null;
Expand All @@ -84,18 +64,8 @@ export const App = () => {

const filter = (event: any) => {
const value = event?.target?.value;
const filteredRoutes = getFilteredRoutes(routes, value);
if (value.length > 0) {
window.history.replaceState(
null,
'',
`${filterPrefix}/${encodeURIComponent(value)}`
);
} else {
window.history.replaceState(null, '', '');
}
setURLHash(value);
setFilterValue(value);
setDisplayedRoutes(filteredRoutes);
};

const _renderShowByContainer = () => {
Expand All @@ -114,22 +84,23 @@ export const App = () => {
</Typography>
<Button
variant="outlined"
onClick={() => setDisplayedRoutes(sortBy('method', displayedRoutes))}
onClick={() => setSort('method')}
startIcon={getSortIcon('method')}
>
Method
</Button>
<Button
variant="outlined"
onClick={() => setDisplayedRoutes(sortBy('path', displayedRoutes))}
onClick={() => setSort('path')}
startIcon={getSortIcon('path')}
>
Path
</Button>
<Button
variant="outlined"
color="error"
onClick={() => setDisplayedRoutes(routes)}
onClick={() => setSort('')}
startIcon={getSortIcon('')}
>
Default
</Button>
Expand Down
39 changes: 39 additions & 0 deletions apps/admin-web/src/app/hooks/useFetchRoutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { MEZZO_API_PATH } from '@caribou-crew/mezzo-constants';
import { RouteItemType, VariantCategory } from '@caribou-crew/mezzo-interfaces';
import { useEffect, useState } from 'react';

export interface URLHashCallback {
routes: RouteItemType[];
initialText: string;
}

/**
* Fetches array of routes via api
* @returns
*/
export default function useFetchRoutes() {
const [routes, setRoutes] = useState<RouteItemType[]>([]);
const [version, setVersion] = useState<string>('');
const [variantCategories, setVariantCategories] = useState<VariantCategory[]>(
[]
);

useEffect(() => {
const fetchData = async () => {
const response = await fetch(`${MEZZO_API_PATH}/routes`);
const data = await response.json();
setRoutes(data.routes);
setVersion(data.appVersion);
setVariantCategories(
(data.variantCategories || []).sort(
(a: VariantCategory, b: VariantCategory) =>
(a?.order ?? 0) - (b?.order ?? 0)
)
);
};

fetchData().catch(console.error);
}, []);

return { routes, version, variantCategories };
}
40 changes: 40 additions & 0 deletions apps/admin-web/src/app/hooks/useFilterFromURL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { RouteItemType } from '@caribou-crew/mezzo-interfaces';
import { useEffect } from 'react';

export interface URLHashCallback {
routes: RouteItemType[];
initialText: string;
}

export type SetFilter = (arg0: string) => void;
const filterPrefix = '#label';

/**
* If #label hash is set in URL on load, then set that value as the initial filter
* @param setFilter
*/
export default function useFilterFromURL(setFilter: SetFilter) {
useEffect(() => {
const hash = getURLHash();
if (hash.key === filterPrefix) {
setFilter(hash.value);
}
}, [setFilter]);
}

export const getURLHash = () => {
const [key, hashValue] = window.location.hash.substring(1).split('/');
return { key, value: decodeURIComponent(hashValue) };
};

export const setURLHash = (value: string) => {
if (value.length > 0) {
window.history.replaceState(
null,
'',
`${filterPrefix}/${encodeURIComponent(value)}`
);
} else {
window.history.replaceState(null, '', '');
}
};
35 changes: 35 additions & 0 deletions apps/admin-web/src/app/hooks/useRouteFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { RouteItemType } from '@caribou-crew/mezzo-interfaces';
import { useState } from 'react';

export interface URLHashCallback {
routes: RouteItemType[];
initialText: string;
}

/**
* Filters array of routes based on the filterValue
* @param routes
* @returns
*/
export default function useRouteFilter(routes: RouteItemType[]) {
const [filterValue, setFilterValue] = useState('');

return {
routes: getFilteredRoutes(routes, filterValue),
filterValue,
setFilterValue,
};
}

const getFilteredRoutes = (routes: RouteItemType[], value: string) => {
const filteredRoutes = routes.filter((route) => {
const searchLower = value?.toLowerCase();
return (
route?.id?.toLowerCase()?.includes(searchLower) ||
route?.label?.toLowerCase()?.includes(searchLower) ||
route?.method?.toLowerCase()?.includes(searchLower) ||
route?.path?.toString()?.toLowerCase()?.includes(searchLower)
);
});
return filteredRoutes;
};
35 changes: 35 additions & 0 deletions apps/admin-web/src/app/hooks/useRouteSort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { RouteItemType } from '@caribou-crew/mezzo-interfaces';
import { useState } from 'react';

export interface URLHashCallback {
routes: RouteItemType[];
initialText: string;
}

/**
* Sorts routes based on selected property and direction
* @param routes
* @returns
*/
export default function useRouteSort(routes: RouteItemType[]) {
const sortAsc = 1;
const [sortedByProperty, setSortedBy] = useState('');
const [sortDirection, setSortDirection] = useState(sortAsc);

const setSort = (property: string) => {
let mySortDirection = sortDirection;
if (sortedByProperty === property) {
mySortDirection *= -1;
setSortDirection(mySortDirection);
} else {
setSortedBy(property);
}
};

const outRoutes = [...routes].sort((a: any, b: any) =>
a?.[sortedByProperty] < b?.[sortedByProperty]
? -1 * sortDirection
: sortDirection
);
return { routes: outRoutes, setSort, sortDirection, sortedByProperty };
}
17 changes: 0 additions & 17 deletions apps/admin-web/src/app/utils/filter.ts

This file was deleted.

31 changes: 0 additions & 31 deletions apps/admin-web/src/app/utils/useSort.ts

This file was deleted.

0 comments on commit 175396a

Please sign in to comment.