parent
f90862f783
commit
7a901543b7
5 changed files with 825 additions and 1394 deletions
File diff suppressed because it is too large
Load Diff
@ -1,123 +1,46 @@ |
|||||||
import Select, { ActionMeta, OnChangeValue } from 'react-select'; |
import { httpGet } from '../../lib/http'; |
||||||
|
import { useEffect, useState } from 'preact/hooks'; |
||||||
|
import { pageProgressMessage } from '../../stores/page'; |
||||||
|
import type { UserProgressResponse } from '../HeroSection/FavoriteRoadmaps'; |
||||||
|
|
||||||
export type RoadmapOptionProps = { |
export type RoadmapOptionProps = { |
||||||
value: string; |
value: string; |
||||||
label: string; |
label: string; |
||||||
}; |
}; |
||||||
|
|
||||||
export interface RoadmapSelectProps { |
export function RoadmapSelect() { |
||||||
options: RoadmapOptionProps[]; |
const [progressList, setProgressList] = useState<UserProgressResponse>(); |
||||||
selectedRoadmaps: RoadmapOptionProps[]; |
|
||||||
setSelectedRoadmap: (roadmap: RoadmapOptionProps[]) => void; |
|
||||||
} |
|
||||||
|
|
||||||
const controlStyles = { |
const fetchProgress = async () => { |
||||||
base: 'border rounded-lg bg-white hover:cursor-pointer', |
const { response, error } = await httpGet<UserProgressResponse>( |
||||||
focus: 'border-primary-600 ring-1 ring-primary-500', |
`${import.meta.env.PUBLIC_API_URL}/v1-get-user-all-progress` |
||||||
nonFocus: 'border-gray-300 hover:border-gray-400', |
); |
||||||
}; |
|
||||||
const placeholderStyles = 'text-gray-500 pl-1 py-0.5'; |
|
||||||
const selectInputStyles = 'pl-1 py-0.5'; |
|
||||||
const valueContainerStyles = 'p-1 gap-1'; |
|
||||||
const singleValueStyles = 'text-sm ml-1'; |
|
||||||
const multiValueStyles = |
|
||||||
'bg-gray-100 rounded items-center py-0.5 pl-2 pr-1 gap-1.5'; |
|
||||||
const multiValueLabelStyles = 'leading-none py-1 text-sm'; |
|
||||||
const multiValueRemoveStyles = |
|
||||||
'border border-gray-200 bg-white hover:bg-red-50 hover:text-red-800 text-gray-500 hover:border-red-300 rounded-md p-0.5'; |
|
||||||
const indicatorsContainerStyles = 'py-0 px-1 gap-1'; |
|
||||||
const clearIndicatorStyles = |
|
||||||
'text-gray-500 p-1 rounded-md hover:bg-red-50 hover:text-red-800'; |
|
||||||
const indicatorSeparatorStyles = 'bg-gray-300'; |
|
||||||
const dropdownIndicatorStyles = |
|
||||||
'p-1 hover:bg-gray-100 text-gray-500 rounded-md hover:text-black'; |
|
||||||
const menuStyles = |
|
||||||
'p-1 mt-2 border border-gray-200 bg-white rounded-lg shadow-lg'; |
|
||||||
const groupHeadingStyles = 'ml-3 mt-2 mb-1 text-gray-500 text-sm'; |
|
||||||
const optionStyles = { |
|
||||||
base: 'hover:cursor-pointer px-3 text-sm py-2 rounded', |
|
||||||
focus: 'bg-gray-100 active:bg-gray-200', |
|
||||||
selected: "after:content-['✔'] after:ml-2 after:text-green-500 text-gray-500", |
|
||||||
}; |
|
||||||
const noOptionsMessageStyles = |
|
||||||
'text-gray-500 p-2 bg-gray-50 border border-dashed border-gray-200 rounded-sm'; |
|
||||||
|
|
||||||
export function RoadmapSelect({ |
if (error || !response) { |
||||||
options, |
|
||||||
selectedRoadmaps, |
|
||||||
setSelectedRoadmap, |
|
||||||
}: RoadmapSelectProps) { |
|
||||||
const onChange = ( |
|
||||||
newValue: OnChangeValue<RoadmapOptionProps, true>, |
|
||||||
actionMeta: ActionMeta<RoadmapOptionProps> |
|
||||||
) => { |
|
||||||
if (actionMeta.action === 'clear') { |
|
||||||
setSelectedRoadmap([]); |
|
||||||
return; |
return; |
||||||
} |
} |
||||||
// Only allow selecting up to 4 roadmaps.
|
|
||||||
if (newValue.length > 4) { |
setProgressList(response); |
||||||
return; |
|
||||||
} |
|
||||||
setSelectedRoadmap(Array.isArray(newValue) ? newValue : [newValue]); |
|
||||||
}; |
}; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
fetchProgress().finally(() => { |
||||||
|
pageProgressMessage.set(''); |
||||||
|
}); |
||||||
|
}, []); |
||||||
|
|
||||||
return ( |
return ( |
||||||
<div> |
<div> |
||||||
{/* @ts-ignore */} |
<div className="relative"> |
||||||
<Select |
<input |
||||||
isMulti |
type="text" |
||||||
options={options} |
className="mb-0.5 w-full rounded-md border p-2 text-sm focus:outline-0 focus:ring-0" |
||||||
onChange={onChange} |
placeholder="Pick roadmaps" |
||||||
value={selectedRoadmaps} |
|
||||||
placeholder="Select roadmaps" |
|
||||||
unstyled |
|
||||||
styles={{ |
|
||||||
input: (base) => ({ |
|
||||||
...base, |
|
||||||
'input:focus': { |
|
||||||
boxShadow: 'none', |
|
||||||
}, |
|
||||||
}), |
|
||||||
// On mobile, the label will truncate automatically, so we want to
|
|
||||||
// override that behaviour.
|
|
||||||
multiValueLabel: (base) => ({ |
|
||||||
...base, |
|
||||||
// whiteSpace: 'normal',
|
|
||||||
// overflow: 'visible',
|
|
||||||
}), |
|
||||||
control: (base) => ({ |
|
||||||
...base, |
|
||||||
transition: 'none', |
|
||||||
}), |
|
||||||
}} |
|
||||||
classNames={{ |
|
||||||
control: ({ isFocused }) => |
|
||||||
`${isFocused ? controlStyles.focus : controlStyles.nonFocus} ${ |
|
||||||
controlStyles.base |
|
||||||
}`,
|
|
||||||
placeholder: () => placeholderStyles, |
|
||||||
input: () => selectInputStyles, |
|
||||||
valueContainer: () => valueContainerStyles, |
|
||||||
singleValue: () => singleValueStyles, |
|
||||||
multiValue: () => multiValueStyles, |
|
||||||
multiValueLabel: () => multiValueLabelStyles, |
|
||||||
multiValueRemove: () => multiValueRemoveStyles, |
|
||||||
indicatorsContainer: () => indicatorsContainerStyles, |
|
||||||
clearIndicator: () => clearIndicatorStyles, |
|
||||||
indicatorSeparator: () => indicatorSeparatorStyles, |
|
||||||
dropdownIndicator: () => dropdownIndicatorStyles, |
|
||||||
menu: () => menuStyles, |
|
||||||
groupHeading: () => groupHeadingStyles, |
|
||||||
option: ({ isFocused, isSelected }) => |
|
||||||
`${isFocused && optionStyles.focus} ${ |
|
||||||
isSelected && optionStyles.selected |
|
||||||
} ${optionStyles.base}`,
|
|
||||||
noOptionsMessage: () => noOptionsMessageStyles, |
|
||||||
}} |
|
||||||
/> |
/> |
||||||
|
<div className="top-full absolute rounded-md"></div> |
||||||
|
</div> |
||||||
|
|
||||||
<div className="mt-1 text-sm text-gray-500">Select up to 4 roadmaps</div> |
<div className="mt-1 text-xs text-gray-500">Select up to 4 roadmaps</div> |
||||||
</div> |
</div> |
||||||
); |
); |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue