Skip to content

Commit

Permalink
Feat/custom search component (#200)
Browse files Browse the repository at this point in the history
* feat: Creating autocomplete component

* fix: Update aria label for copy badge

* fix: Update aria labels and components for wcag compliance

* fix: Update aria label for wcag compliance

* chore: Remove old autocomplete

* feat: Create a beautiful accessible autocomplete component

* fix: Update handling of cookies so that they get persisted properly

* fix: Update styling to match closely to location input

* fix: Fix weird bugs with location bar

* feat: Update search layout to use a form and to submit search on enter

* fix: Fix rendering issues

* chore: Move around imports

* fix: Fix issues with input

* feat: Move submit functionality to wrapping form

* feat: Optimize hook

* feat: Add prev search terms for tracking for autocomplete

* fix: Only auto select when valid coords are not set

* fix: Separate userCoordinates from searchCoordinates

* chore: Use new searchCoordinates

* fix: Open suggestion dropdown on typing

* fix: On hover now properly displays the hovered value

* fix: Use new searchCoordinates for disabled status

* fix: Set userCoordinates after the new params have been added
  • Loading branch information
devcshort authored Oct 15, 2024
1 parent 176ca42 commit 536b184
Show file tree
Hide file tree
Showing 15 changed files with 940 additions and 274 deletions.
65 changes: 65 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
},
"dependencies": {
"@azure-rest/ai-translation-text": "^1.0.0-beta.1",
"@popperjs/core": "^2.11.8",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
Expand Down Expand Up @@ -86,6 +87,7 @@
"react-cookie": "^4.1.1",
"react-dom": "18.2.0",
"react-i18next": "^13.0.1",
"react-popper": "^2.3.0",
"react-to-print": "^2.14.13",
"sharp": "^0.32.1",
"sonner": "^1.5.0",
Expand Down
6 changes: 5 additions & 1 deletion src/shared/components/copy-badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ export function CopyBadge({ children, text, href }: CopyBadgeProps) {

<TooltipProvider>
<Tooltip open={copied}>
<TooltipTrigger className="w-4 shrink-0" onClick={handleCopy}>
<TooltipTrigger
className="w-4 shrink-0"
onClick={handleCopy}
aria-label="Copy"
>
{copied ? (
<CheckIcon className="size-4" />
) : (
Expand Down
27 changes: 16 additions & 11 deletions src/shared/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ export function Header(props: Props) {
}
}}
>
<SelectTrigger className="w-[150px]">
<SelectTrigger
className="w-[150px]"
aria-label={t('header.language_select_label')}
>
<div className="flex items-center gap-1 overflow-hidden">
<LanguagesIcon className="size-4" />
<SelectValue
Expand All @@ -160,19 +163,21 @@ export function Header(props: Props) {
</Fragment>,
<Fragment key="4">
{session.status === 'authenticated' && (
<Button
variant="ghost"
className="flex gap-1"
onClick={() => {
signOut({ redirect: true, callbackUrl: '/' });
}}
>
<LogOutIcon className="size-4" /> {t('header.log_out')}
</Button>
<li>
<Button
variant="ghost"
className="flex gap-1"
onClick={() => {
signOut({ redirect: true, callbackUrl: '/' });
}}
>
<LogOutIcon className="size-4" /> {t('header.log_out')}
</Button>
</li>
)}
</Fragment>,
],
[session.status, t, router, appConfig],
[session.status, t, router, appConfig, setDialogStore],
);

return (
Expand Down
25 changes: 20 additions & 5 deletions src/shared/components/jotai-hydration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { useHydrateAndSyncAtoms } from '@/shared/hooks/use-hydrate-and-sync-atoms';
import { searchAtom } from '@/shared/store/search';
import { useAppConfig } from '../hooks/use-app-config';
import { parseCookies } from 'nookies';
import { parseCookies, setCookie } from 'nookies';
import {
USER_PREF_COORDS,
USER_PREF_DISTANCE,
Expand All @@ -22,10 +22,12 @@ import { deviceAtom } from '../store/device';

function getCoordinates(pageProps, cookies) {
if (pageProps.coords) {
return decodeURIComponent(pageProps.coords)
const coords = decodeURIComponent(pageProps.coords)
.split(',')
.map((number) => parseFloat(number))
.filter((number) => !isNaN(number));
setCookie(null, USER_PREF_COORDS, coords.join(','), { path: '/' });
return coords;
} else if (cookies[USER_PREF_COORDS]) {
return cookies[USER_PREF_COORDS].split(',')
.map((number) => parseFloat(number))
Expand All @@ -35,6 +37,18 @@ function getCoordinates(pageProps, cookies) {
return [];
}

function getSearchLocation(pageProps, cookies) {
if (pageProps.location) {
const location = decodeURIComponent(pageProps.location);
setCookie(null, USER_PREF_LOCATION, location, { path: '/' });
return location;
} else if (cookies[USER_PREF_LOCATION]) {
return cookies[USER_PREF_LOCATION];
}

return '';
}

// This component handles the hydration of Jotai state as well as keeping it in sync with re-renders/fetches of new data
// This MUST be a child of the Jotai Provider component or hydration will not work
export function JotaiHydration({ pageProps }) {
Expand Down Expand Up @@ -67,17 +81,18 @@ export function JotaiHydration({ pageProps }) {
searchAtom,
{
searchTerm: pageProps?.query_label ?? '',
prevSearchTerm: pageProps?.query_label ?? '',
query: pageProps?.query ?? '',
queryLabel: pageProps?.query_label ?? '',
searchDistance:
pageProps?.distance ??
cookies?.[USER_PREF_DISTANCE] ??
appConfig?.search?.defaultRadius?.toString() ??
'0',
searchLocation:
pageProps?.location ?? cookies?.[USER_PREF_LOCATION] ?? '',
searchLocation: getSearchLocation(pageProps, cookies),
prevSearchLocation: getSearchLocation(pageProps, cookies),
searchLocationValidationError: '',
userLocation: pageProps?.location,
searchCoordinates: getCoordinates(pageProps, cookies),
userCoordinates: getCoordinates(pageProps, cookies),
},
],
Expand Down
12 changes: 8 additions & 4 deletions src/shared/components/search/distance-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import { useAppConfig } from '../../hooks/use-app-config';
import { useAtomValue, useSetAtom } from 'jotai';
import {
searchAtom,
searchCoordinatesAtom,
searchDistanceAtom,
searchLocationAtom,
userCoordinatesAtom,
} from '../../store/search';
import { setCookie } from 'nookies';
import { USER_PREF_DISTANCE } from '../../lib/constants';
Expand All @@ -23,7 +22,7 @@ export function DistanceSelect() {
const { t } = useTranslation();
const appConfig = useAppConfig();
const setSearch = useSetAtom(searchAtom);
const coords = useAtomValue(userCoordinatesAtom);
const coords = useAtomValue(searchCoordinatesAtom);
const distance = useAtomValue(searchDistanceAtom);

const hasLocation = coords?.length == 2;
Expand All @@ -42,7 +41,12 @@ export function DistanceSelect() {
value={distance}
disabled={!hasLocation}
>
<SelectTrigger className="w-[125px]">
<SelectTrigger
className="w-[125px] rounded-none border-none shadow-none"
aria-label={t('search.radius_placeholder', {
defaultValue: 'radius',
})}
>
<SelectValue
placeholder={t('search.radius_placeholder', {
defaultValue: 'radius',
Expand Down
Loading

0 comments on commit 536b184

Please sign in to comment.