Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DonovanAndrews300 committed Jan 20, 2025
1 parent 39af6af commit 91b7a8e
Show file tree
Hide file tree
Showing 8 changed files with 332 additions and 46 deletions.
13 changes: 12 additions & 1 deletion src/components/FilterView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { FC } from 'react';
import { PiX } from 'react-icons/pi';
import { ThemeButton } from './ThemeButton';
import { BarClickOptions } from '@/app/find-properties/[[...opa_id]]/page';
import { rcos, neighborhoods, zoning } from './Filters/filterOptions';
import {
rcos,
neighborhoods,
zoning,
marketValues,
} from './Filters/filterOptions';
import DimensionFilter from './Filters/DimensionFilter';

const filters = [
Expand All @@ -14,6 +19,12 @@ const filters = [
options: ['Low', 'Medium', 'High'],
type: 'buttonGroup',
},
{
property: 'market_value',
display: 'Market Value',
options: marketValues,
type: 'range',
},
{
property: 'get_access',
display: 'Get Access',
Expand Down
59 changes: 59 additions & 0 deletions src/components/Filters/AutoComplete.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use client';

import React, { FC } from 'react';
import {
AutocompleteFilter,
AutocompleteFilterItem,
} from './AutoCompleteVariants';

type AutocompleteProps = {
display: string;
options: string[];
limitType: string;
selectedRange: string | React.ChangeEvent<HTMLSelectElement>;
setSelectedRange: (prev: any) => void;
aria_describedby_label?: string;
handleSelectionChange: (selection: string, limitType: string) => void;
};

export const Autocomplete: FC<AutocompleteProps> = ({
options,
limitType,
selectedRange,
setSelectedRange,
aria_describedby_label,
handleSelectionChange,
}) => {
const selectedKey = options.indexOf(selectedRange as string).toString();

const onEnter = (key: string) => {
setSelectedRange((prev: any) => ({
...prev,
[limitType]: key,
}));
handleSelectionChange(key, limitType);
};
return (
<div className="space-x-2 min-h-[33.5px]">
<AutocompleteFilter
aria-describedby={aria_describedby_label}
defaultSelectedKey={selectedKey}
variant="flat"
size="md"
radius="md"
onKeyUp={(key) =>
key.key === 'Enter' && onEnter(key.currentTarget.value)
}
placeholder="Select options..."
>
{options.map((option: string, index: number) => (
<AutocompleteFilterItem key={index} shouldHighlightOnFocus={false}>
{option}
</AutocompleteFilterItem>
))}
</AutocompleteFilter>
</div>
);
};

export default Autocomplete;
43 changes: 43 additions & 0 deletions src/components/Filters/AutoCompleteVariants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {
Autocomplete,
AutocompleteItem,
extendVariants,
} from '@nextui-org/react';

export const AutocompleteFilterItem = extendVariants(AutocompleteItem, {
variants: {
color: {
gray: {
title: ['text-gray-900'],
},
},
size: {
md: {
wrapper: 'm-12',
},
},
},
defaultVariants: {
color: 'gray',
size: 'md',
},
});

export const AutocompleteFilter = extendVariants(Autocomplete, {
variants: {
color: {
gray: {
base: 'text-gray-900',
},
},
size: {
md: {
base: 'py-2',
},
},
},
defaultVariants: {
color: 'gray',
size: 'md',
},
});
101 changes: 75 additions & 26 deletions src/components/Filters/DimensionFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useFilter } from '@/context/FilterContext';
import ButtonGroup from './ButtonGroup';
import MultiSelect from './MultiSelect';
import Panels from './Panels';
import RangedInputs from './RangedInputs';

type DimensionFilterProps = {
property: string;
Expand Down Expand Up @@ -36,10 +37,17 @@ const DimensionFilter: FC<DimensionFilterProps> = ({
const [selectedKeys, setSelectedKeys] = useState<string[]>(
appFilter[property]?.values || []
);
const [selectedRanges, setSelectedRanges] = useState<{
min: string | React.ChangeEvent<HTMLSelectElement>;
max: string | React.ChangeEvent<HTMLSelectElement>;
}>({
min: appFilter[property]?.rangedValues?.min as string,
max: appFilter[property]?.rangedValues?.max as string,
});
const initialSelectedPanelKeys = () => {
const panelKeyObj: { [key: string]: string[] } = {};
for (const key in appFilter) {
panelKeyObj[key] = appFilter[key].values;
panelKeyObj[key] = appFilter[key].values || [];
}
return panelKeyObj;
};
Expand Down Expand Up @@ -87,9 +95,20 @@ const DimensionFilter: FC<DimensionFilterProps> = ({
};

const handleSelectionChange = (
selection: React.ChangeEvent<HTMLSelectElement> | string
selection: React.ChangeEvent<HTMLSelectElement> | string,
limitType?: string
) => {
let newMultiSelect: string[] = [];
const newRangeValues = { ...selectedRanges };

if (limitType) {
if (limitType === 'min') {
newRangeValues.min = selection;
} else if (limitType === 'max') {
newRangeValues.max = selection;
}
}

if (typeof selection === 'string') {
newMultiSelect = selectedKeys.includes(selection)
? selectedKeys.filter((key) => key !== selection)
Expand All @@ -99,13 +118,23 @@ const DimensionFilter: FC<DimensionFilterProps> = ({
newMultiSelect = selection.target.value.split(',');
}
}
setSelectedKeys(newMultiSelect);
dispatch({
type: 'SET_DIMENSIONS',
property,
dimensions: newMultiSelect,
useIndexOfFilter,
});
if (limitType) {
dispatch({
type: 'SET_DIMENSIONS',
property,
limitType,
dimensions: newRangeValues,
useIndexOfFilter,
});
} else {
setSelectedKeys(newMultiSelect);
dispatch({
type: 'SET_DIMENSIONS',
property,
dimensions: newMultiSelect,
useIndexOfFilter,
});
}
};

const filter = useMemo(() => {
Expand All @@ -130,14 +159,25 @@ const DimensionFilter: FC<DimensionFilterProps> = ({
aria_describedby_label={filterLabelID}
/>
);
} else if (type === 'range') {
return (
<RangedInputs
display={display}
options={options}
selectedRanges={appFilter[property]?.rangedValues}
setSelectedRanges={setSelectedRanges}
handleSelectionChange={handleSelectionChange}
aria_describedby_label={filterLabelID}
/>
);
} else {
return (
<MultiSelect
display={display}
options={options}
selectedKeys={selectedKeys}
toggleDimension={toggleDimension}
handleSelectionChange={handleSelectionChange}
handleSelectionChange={handleSelectionChange as any}
aria_describedby_label={filterLabelID}
/>
);
Expand All @@ -150,10 +190,15 @@ const DimensionFilter: FC<DimensionFilterProps> = ({
desc: 'Find properties based on how much they can reduce gun violence considering the gun violence, cleanliness, and tree canopy nearby. ',
linkFragment: 'priority-method',
}
: {
desc: 'Find properties based on what we think is the easiest method to get legal access to them, based on the data available to us. ',
linkFragment: 'access-method',
};
: property === 'market_value'
? {
desc: 'Find properties based on their market value (USD). ',
linkFragment: 'access-method',
}
: {
desc: 'Find properties based on what we think is the easiest method to get legal access to them, based on the data available to us. ',
linkFragment: 'access-method',
};

// text-gray-500, 600 ? or #586266 (figma)?
return (
Expand All @@ -162,20 +207,24 @@ const DimensionFilter: FC<DimensionFilterProps> = ({
<h2 className="heading-lg" id={filterLabelID}>
{display}
</h2>
{(property === 'get_access' || property === 'priority_level') && (
{(property === 'get_access' ||
property === 'priority_level' ||
property === 'market_value') && (
<p className="body-sm text-gray-500 w-[90%] my-1">
{filterDescription.desc}
<a
href={`/methodology/#${filterDescription.linkFragment}`}
className="link"
aria-label={`Learn more about ${
property === 'priority_level'
? 'priority level'
: 'access process'
} from our Methodology Page`}
>
Learn more{' '}
</a>
{(property === 'get_access' || property === 'priority_level') && (
<a
href={`/methodology/#${filterDescription.linkFragment}`}
className="link"
aria-label={`Learn more about ${
property === 'priority_level'
? 'priority level'
: 'access process'
} from our Methodology Page`}
>
Learn more{' '}
</a>
)}
</p>
)}
</div>
Expand Down
71 changes: 71 additions & 0 deletions src/components/Filters/RangedInputs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use client';

import React, { FC } from 'react';
import Autocomplete from './AutoComplete';

type RangedInputsProps = {
display: string;
options: string[];
selectedRanges:
| {
min: string | React.ChangeEvent<HTMLSelectElement>;
max: string | React.ChangeEvent<HTMLSelectElement>;
}
| undefined;
setSelectedRanges: (prev: any) => void;
aria_describedby_label?: string;
handleSelectionChange: (selection: string) => void;
};

const RangedInputs: FC<RangedInputsProps> = ({
display,
options,
selectedRanges,
setSelectedRanges,
aria_describedby_label,
handleSelectionChange,
}) => {
return (
<div className="flex items-center min-h-[40px]">
<div className="flex flex-col">
<label
htmlFor="max"
className="body-sm font-medium text-gray-700"
aria-describedby={aria_describedby_label}
>
Min
</label>
<Autocomplete
display={display}
limitType={'min'}
selectedRange={selectedRanges?.min ?? ''}
setSelectedRange={setSelectedRanges}
options={options}
aria_describedby_label=""
handleSelectionChange={handleSelectionChange}
/>
</div>
<div className="flex items-center justify-center mt-6 h-0.5 w-5 bg-gray-400"></div>
<div className="flex flex-col">
<label
htmlFor="max"
className="body-sm font-medium text-gray-700"
aria-describedby={aria_describedby_label}
>
Max
</label>
<Autocomplete
display={display}
limitType={'max'}
selectedRange={selectedRanges?.max ?? ''}
setSelectedRange={setSelectedRanges}
options={options}
aria_describedby_label=""
handleSelectionChange={handleSelectionChange}
/>
</div>
</div>
);
};

export default RangedInputs;
9 changes: 9 additions & 0 deletions src/components/Filters/filterOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ export const neighborhoods: string[] = [
'Yorktown',
];

export const marketValues: string[] = [
'$10,000',
'$20,000',
'$30,000',
'$40,000',
'$50,000',
'$60,000',
];

export const rcos: string[] = [
'10th Democratic Ward',
'12th Ward Democratic Committee',
Expand Down
Loading

0 comments on commit 91b7a8e

Please sign in to comment.