Refactor profile and form

pull/5494/head
Kamran Ahmed 8 months ago
parent 3cb31da862
commit 7600b1af89
  1. 2
      src/components/Navigation/AccountDropdownList.tsx
  2. 15
      src/components/RoadCard/SelectionButton.tsx
  3. 17
      src/components/UpdateProfile/UpdateProfileForm.tsx
  4. 57
      src/components/UpdateProfile/UpdatePublicProfileForm.tsx
  5. 48
      src/components/UserPublicProfile/UserPublicProgresses.tsx

@ -20,7 +20,7 @@ export function AccountDropdownList(props: AccountDropdownListProps) {
className="group flex items-center gap-2 rounded py-2 pl-3 pr-2 text-sm font-medium text-slate-100 hover:bg-slate-700" className="group flex items-center gap-2 rounded py-2 pl-3 pr-2 text-sm font-medium text-slate-100 hover:bg-slate-700"
> >
<User2 className="h-4 w-4 stroke-[2.5px] text-slate-400 group-hover:text-white" /> <User2 className="h-4 w-4 stroke-[2.5px] text-slate-400 group-hover:text-white" />
Profile Account
</a> </a>
</li> </li>
<li className="px-1"> <li className="px-1">

@ -1,7 +1,9 @@
import type { ButtonHTMLAttributes } from 'react'; import type { ButtonHTMLAttributes } from 'react';
import { cn } from '../../lib/classname'; import { cn } from '../../lib/classname';
import type { LucideIcon } from 'lucide-react';
type SelectionButtonProps = { type SelectionButtonProps = {
icon?: LucideIcon;
text: string; text: string;
isDisabled: boolean; isDisabled: boolean;
isSelected: boolean; isSelected: boolean;
@ -9,13 +11,21 @@ type SelectionButtonProps = {
} & ButtonHTMLAttributes<HTMLButtonElement>; } & ButtonHTMLAttributes<HTMLButtonElement>;
export function SelectionButton(props: SelectionButtonProps) { export function SelectionButton(props: SelectionButtonProps) {
const { text, isDisabled, isSelected, onClick, className, ...rest } = props; const {
icon: Icon,
text,
isDisabled,
isSelected,
onClick,
className,
...rest
} = props;
return ( return (
<button <button
{...rest} {...rest}
className={cn( className={cn(
'rounded-md border p-1 px-2 text-sm', 'rounded-md flex items-center border p-1 px-2 text-sm',
isSelected ? 'border-gray-500 bg-gray-300' : '', isSelected ? 'border-gray-500 bg-gray-300' : '',
!isDisabled ? 'cursor-pointer' : 'cursor-not-allowed opacity-40', !isDisabled ? 'cursor-pointer' : 'cursor-not-allowed opacity-40',
className, className,
@ -23,6 +33,7 @@ export function SelectionButton(props: SelectionButtonProps) {
disabled={isDisabled} disabled={isDisabled}
onClick={onClick} onClick={onClick}
> >
{Icon && <Icon size={13} className="mr-1.5" />}
{text} {text}
</button> </button>
); );

@ -101,12 +101,17 @@ export function UpdateProfileForm() {
/> />
</div> </div>
<div className="flex w-full flex-col"> <div className="flex w-full flex-col">
<label <div className="flex items-center justify-between">
htmlFor="email" <label
className='text-sm leading-none text-slate-500 after:text-red-400 after:content-["*"]' htmlFor="email"
> className='text-sm leading-none text-slate-500 after:text-red-400 after:content-["*"]'
Email >
</label> Email
</label>
<a href='/account/settings' className="text-purple-700 text-xs underline hover:text-purple-800">
Visit settings page to change email
</a>
</div>
<input <input
type="email" type="email"
name="email" name="email"

@ -8,8 +8,9 @@ import type {
UserDocument, UserDocument,
} from '../../api/user'; } from '../../api/user';
import { SelectionButton } from '../RoadCard/SelectionButton'; import { SelectionButton } from '../RoadCard/SelectionButton';
import { ArrowUpRight } from 'lucide-react'; import { ArrowUpRight, Globe, LockIcon } from 'lucide-react';
import { useToast } from '../../hooks/use-toast'; import { useToast } from '../../hooks/use-toast';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
type RoadmapType = { type RoadmapType = {
id: string; id: string;
@ -28,6 +29,7 @@ export function UpdatePublicProfileForm() {
const toast = useToast(); const toast = useToast();
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
const [publicProfileUrl, setPublicProfileUrl] = useState(''); const [publicProfileUrl, setPublicProfileUrl] = useState('');
const [isAvailableForHire, setIsAvailableForHire] = useState(false); const [isAvailableForHire, setIsAvailableForHire] = useState(false);
const [isEmailVisible, setIsEmailVisible] = useState(true); const [isEmailVisible, setIsEmailVisible] = useState(true);
@ -186,6 +188,10 @@ export function UpdatePublicProfileForm() {
return ( return (
<> <>
{isCreatingRoadmap && (
<CreateRoadmapModal onClose={() => setIsCreatingRoadmap(false)} />
)}
<div className="mt-10 flex items-center justify-between gap-2"> <div className="mt-10 flex items-center justify-between gap-2">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<h3 className="text-2xl font-bold">Public Profile</h3> <h3 className="text-2xl font-bold">Public Profile</h3>
@ -200,6 +206,7 @@ export function UpdatePublicProfileForm() {
<SelectionButton <SelectionButton
type="button" type="button"
text="Public" text="Public"
icon={Globe}
isDisabled={profileVisibility === 'public'} isDisabled={profileVisibility === 'public'}
isSelected={profileVisibility === 'public'} isSelected={profileVisibility === 'public'}
onClick={() => updateProfileVisibility('public')} onClick={() => updateProfileVisibility('public')}
@ -207,6 +214,7 @@ export function UpdatePublicProfileForm() {
<SelectionButton <SelectionButton
type="button" type="button"
text="Private" text="Private"
icon={LockIcon}
isDisabled={profileVisibility === 'private'} isDisabled={profileVisibility === 'private'}
isSelected={profileVisibility === 'private'} isSelected={profileVisibility === 'private'}
onClick={() => updateProfileVisibility('private')} onClick={() => updateProfileVisibility('private')}
@ -262,7 +270,9 @@ export function UpdatePublicProfileForm() {
</div> </div>
<div className="rounded-md border p-4"> <div className="rounded-md border p-4">
<h3 className="text-sm font-medium">Show my Learning Activity</h3> <h3 className="text-sm font-medium">
Pick the roadmaps to show your progress
</h3>
<div className="mt-3 flex items-center gap-2"> <div className="mt-3 flex items-center gap-2">
<SelectionButton <SelectionButton
type="button" type="button"
@ -276,7 +286,7 @@ export function UpdatePublicProfileForm() {
/> />
<SelectionButton <SelectionButton
type="button" type="button"
text="Hide my Activity" text="Hide my Progress"
isDisabled={false} isDisabled={false}
isSelected={roadmapVisibility === 'none'} isSelected={roadmapVisibility === 'none'}
onClick={() => { onClick={() => {
@ -286,7 +296,9 @@ export function UpdatePublicProfileForm() {
/> />
</div> </div>
<h3 className="mt-4 text-sm font-medium">Only Following Roadmaps</h3> <h3 className="mt-4 text-sm font-medium">
Only show the selected roadmaps
</h3>
{publicRoadmaps.length > 0 ? ( {publicRoadmaps.length > 0 ? (
<div className="mt-3 flex flex-wrap items-center gap-2"> <div className="mt-3 flex flex-wrap items-center gap-2">
{publicRoadmaps.map((r) => ( {publicRoadmaps.map((r) => (
@ -326,7 +338,9 @@ export function UpdatePublicProfileForm() {
</div> </div>
<div className="rounded-md border p-4"> <div className="rounded-md border p-4">
<h3 className="text-sm font-medium">Show my Custom Roadmaps</h3> <h3 className="text-sm font-medium">
Pick the custom roadmaps to show on your profile
</h3>
<div className="mt-3 flex items-center gap-2"> <div className="mt-3 flex items-center gap-2">
<SelectionButton <SelectionButton
type="button" type="button"
@ -350,7 +364,9 @@ export function UpdatePublicProfileForm() {
/> />
</div> </div>
<h3 className="mt-4 text-sm font-medium">Only Following Roadmaps</h3> <h3 className="mt-4 text-sm font-medium">
Only show the following selected custom roadmaps
</h3>
{publicCustomRoadmaps.length > 0 ? ( {publicCustomRoadmaps.length > 0 ? (
<div className="mt-3 flex flex-wrap items-center gap-2"> <div className="mt-3 flex flex-wrap items-center gap-2">
{publicCustomRoadmaps.map((r) => ( {publicCustomRoadmaps.map((r) => (
@ -377,11 +393,18 @@ export function UpdatePublicProfileForm() {
))} ))}
</div> </div>
) : ( ) : (
<p className="mt-2 rounded-lg bg-yellow-100 p-2 text-yellow-700"> <p className="mt-2 rounded-lg bg-yellow-100 p-2 text-sm text-yellow-700">
You have not created any custom roadmaps yet.{' '} You do not have any custom roadmaps.{' '}
<a href="/roadmaps" className="text-black underline"> <button
Create a custom roadmap type={'button'}
</a> className="font-medium underline underline-offset-2 hover:text-yellow-800"
onClick={() => {
setIsCreatingRoadmap(true);
}}
>
Create one now
</button>
.
</p> </p>
)} )}
</div> </div>
@ -471,7 +494,7 @@ export function UpdatePublicProfileForm() {
</label> </label>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex select-none items-center gap-2">
<input <input
type="checkbox" type="checkbox"
name="isAvailableForHire" name="isAvailableForHire"
@ -483,10 +506,12 @@ export function UpdatePublicProfileForm() {
Available for Hire Available for Hire
</label> </label>
</div> </div>
<p className="mt-1 text-sm text-slate-500"> {isAvailableForHire && (
Enable this if you are open to job opportunities, we will show a <p className="mt-1 text-sm text-slate-500">
badge on your profile to indicate that you are available for hire. Make sure to keep your progress updated for
</p> potential employers.
</p>
)}
</div> </div>
<button <button

@ -58,35 +58,29 @@ export function UserPublicProgresses(props: UserPublicProgressesProps) {
</> </>
)} )}
{customRoadmapVisibility !== 'none' && ( {customRoadmapVisibility !== 'none' && customRoadmaps?.length > 0 && (
<> <>
<h2 className="mt-6 text-xs uppercase text-gray-400">My Roadmaps</h2> <h2 className="mt-6 text-xs uppercase text-gray-400">My Roadmaps</h2>
{customRoadmaps?.length === 0 ? ( <ul className="mt-4 grid grid-cols-2 gap-2 max-md:grid-cols-1">
<div className="mt-4 text-sm text-gray-500"> {customRoadmaps.map((roadmap, counter) => (
No roadmaps added yet. <li key={roadmap.id + counter}>
</div> <UserPublicProgressStats
) : ( updatedAt={roadmap.updatedAt}
<ul className="mt-4 grid grid-cols-2 gap-2 max-md:grid-cols-1"> title={roadmap.title}
{customRoadmaps.map((roadmap, counter) => ( totalCount={roadmap.total}
<li key={roadmap.id + counter}> doneCount={roadmap.done}
<UserPublicProgressStats learningCount={roadmap.learning}
updatedAt={roadmap.updatedAt} skippedCount={roadmap.skipped}
title={roadmap.title} resourceId={roadmap.id}
totalCount={roadmap.total} resourceType="roadmap"
doneCount={roadmap.done} roadmapSlug={roadmap.roadmapSlug}
learningCount={roadmap.learning} username={username!}
skippedCount={roadmap.skipped} isCustomResource={true}
resourceId={roadmap.id} userId={userId}
resourceType="roadmap" />
roadmapSlug={roadmap.roadmapSlug} </li>
username={username!} ))}
isCustomResource={true} </ul>
userId={userId}
/>
</li>
))}
</ul>
)}
</> </>
)} )}
</div> </div>

Loading…
Cancel
Save