[offers][refactor] tweak profile page UI

pull/500/head
Yangshun Tay 2 years ago
parent 4b327b5132
commit 36541b5244

@ -37,28 +37,28 @@ export default function DashboardProfileCard({
</h4> </h4>
<div className="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-4"> <div className="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-4">
{company?.name && ( {company?.name && (
<div className="mt-2 flex items-center text-sm text-gray-500"> <div className="mt-2 flex items-center text-sm text-slate-500">
<BuildingOfficeIcon <BuildingOfficeIcon
aria-hidden="true" aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/> />
{company.name} {company.name}
</div> </div>
)} )}
{location && ( {location && (
<div className="mt-2 flex items-center text-sm text-gray-500"> <div className="mt-2 flex items-center text-sm text-slate-500">
<MapPinIcon <MapPinIcon
aria-hidden="true" aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/> />
{location.cityName} {location.cityName}
</div> </div>
)} )}
{level && ( {level && (
<div className="mt-2 flex items-center text-sm text-gray-500"> <div className="mt-2 flex items-center text-sm text-slate-500">
<ArrowTrendingUpIcon <ArrowTrendingUpIcon
aria-hidden="true" aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/> />
{level} {level}
</div> </div>

@ -13,12 +13,12 @@ export default function EducationCard({
education: { type, field, startDate, endDate, school }, education: { type, field, startDate, endDate, school },
}: Props) { }: Props) {
return ( return (
<div className="mx-8 my-4 block rounded-lg bg-white py-4 shadow-md"> <div className="block rounded-lg border border-slate-200 bg-white p-4 text-sm ">
<div className="flex justify-between px-8"> <div className="flex justify-between">
<div className="flex flex-col"> <div>
<div className="flex flex-row"> <div className="flex items-center">
<LightBulbIcon className="mr-1 h-5" /> <LightBulbIcon className="mr-1 h-5" />
<span className="ml-1 font-bold"> <span className="text-semibold ml-1">
{field ? `${type ?? 'N/A'}, ${field}` : type ?? `N/A`} {field ? `${type ?? 'N/A'}, ${field}` : type ?? `N/A`}
</span> </span>
</div> </div>

@ -1,17 +1,13 @@
import { import {
BuildingOffice2Icon, ArrowTrendingUpIcon,
ChatBubbleBottomCenterTextIcon, BuildingOfficeIcon,
CurrencyDollarIcon, MapPinIcon,
ScaleIcon, } from '@heroicons/react/20/solid';
} from '@heroicons/react/24/outline';
import { HorizontalDivider } from '@tih/ui';
import { JobTypeLabel } from '~/components/offers/constants';
import type { OfferDisplayData } from '~/components/offers/types'; import type { OfferDisplayData } from '~/components/offers/types';
import { import { getLocationDisplayText } from '~/utils/offers/string';
getCompanyDisplayText,
getJobDisplayText,
} from '~/utils/offers/string';
type Props = Readonly<{ type Props = Readonly<{
offer: OfferDisplayData; offer: OfferDisplayData;
@ -37,33 +33,56 @@ export default function OfferCard({
}: Props) { }: Props) {
function UpperSection() { function UpperSection() {
return ( return (
<div className="flex justify-between px-8"> <div className="px-4 py-5 sm:px-6">
<div className="flex flex-col"> <div className="flex justify-between">
{(companyName || location) && ( <div>
<div className="flex flex-row"> <h3 className="text-lg font-medium leading-6 text-slate-900">
<span> {jobTitle} {jobType && <>({JobTypeLabel[jobType]})</>}
<BuildingOffice2Icon className="mr-3 h-5" /> </h3>
</span> <div className="mt-1 flex flex-row flex-wrap space-x-4 sm:mt-0">
<span className="font-bold"> {companyName && (
{getCompanyDisplayText(companyName, location)} <div className="mt-2 flex items-center text-sm text-slate-500">
</span> <BuildingOfficeIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/>
{companyName}
</div>
)}
{location && (
<div className="mt-2 flex items-center text-sm text-slate-500">
<MapPinIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/>
{getLocationDisplayText(location)}
</div>
)}
{jobLevel && (
<div className="mt-2 flex items-center text-sm text-slate-500">
<ArrowTrendingUpIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/>
{jobLevel}
</div> </div>
)} )}
<div className="ml-8 flex flex-row">
<p>{getJobDisplayText(jobTitle, jobLevel, jobType)}</p>
</div> </div>
</div> </div>
<div className="space-y-2">
{!duration && receivedMonth && ( {!duration && receivedMonth && (
<div className="font-light text-slate-400"> <div className="text-sm text-slate-500">
<p>{receivedMonth}</p> <p>{receivedMonth}</p>
</div> </div>
)} )}
{duration && ( {duration && (
<div className="font-light text-slate-400"> <div className="text-sm text-slate-500">
<p>{`${duration} months`}</p> <p>{`${duration} months`}</p>
</div> </div>
)} )}
</div> </div>
</div>
</div>
); );
} }
@ -78,60 +97,69 @@ export default function OfferCard({
} }
return ( return (
<> <div className="border-t border-slate-200 px-4 py-5 sm:px-6">
<HorizontalDivider /> <dl className="grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-4">
<div className="px-8"> {totalCompensation && (
<div className="flex flex-col py-2"> <div className="col-span-1">
{(totalCompensation || monthlySalary) && ( <dt className="text-sm font-medium text-slate-500">
<div className="flex flex-row"> Total Compensation
<span> </dt>
<CurrencyDollarIcon className="mr-3 h-5" /> <dd className="mt-1 text-sm text-slate-900">
</span> {totalCompensation}
<span> </dd>
<p>
{totalCompensation && `TC: ${totalCompensation}`}
{monthlySalary && `Monthly Salary: ${monthlySalary}`}
</p>
</span>
</div> </div>
)} )}
{(base || stocks || bonus) && totalCompensation && ( {monthlySalary && (
<div className="ml-8 flex flex-row font-light"> <div className="col-span-1">
<p> <dt className="text-sm font-medium text-slate-500">
Base / year: {base ?? 'N/A'} Stocks / year:{' '} Monthly Salary
{stocks ?? 'N/A'} Bonus / year: {bonus ?? 'N/A'} </dt>
</p> <dd className="mt-1 text-sm text-slate-900">{monthlySalary}</dd>
</div> </div>
)} )}
{base && (
<div className="col-span-1">
<dt className="text-sm font-medium text-slate-500">
Base Salary
</dt>
<dd className="mt-1 text-sm text-slate-900">{base}</dd>
</div> </div>
{negotiationStrategy && ( )}
<div className="flex flex-col py-2"> {stocks && (
<div className="flex flex-row"> <div className="col-span-1">
<span> <dt className="text-sm font-medium text-slate-500">Stocks</dt>
<ScaleIcon className="h-5 w-5" /> <dd className="mt-1 text-sm text-slate-900">{stocks}</dd>
</span>
<span className="overflow-wrap ml-2">
"{negotiationStrategy}"
</span>
</div> </div>
)}
{bonus && (
<div className="col-span-1">
<dt className="text-sm font-medium text-slate-500">Bonus</dt>
<dd className="mt-1 text-sm text-slate-900">{bonus}</dd>
</div> </div>
)} )}
{otherComment && ( {negotiationStrategy && (
<div className="flex flex-col py-2"> <div className="col-span-2">
<div className="flex flex-row"> <dt className="text-sm font-medium text-slate-500">
<span> Negotiation Strategy
<ChatBubbleBottomCenterTextIcon className="h-5 w-5" /> </dt>
</span> <dd className="mt-1 text-sm text-slate-900">
<span className="overflow-wrap ml-2">"{otherComment}"</span> {negotiationStrategy}
</dd>
</div> </div>
)}
{otherComment && (
<div className="col-span-2">
<dt className="text-sm font-medium text-slate-500">Others</dt>
<dd className="mt-1 text-sm text-slate-900">{otherComment}</dd>
</div> </div>
)} )}
</dl>
</div> </div>
</>
); );
} }
return ( return (
<div className="mx-8 my-4 block rounded-md border-b border-gray-300 bg-white py-4"> <div className="block rounded-lg border border-slate-200 bg-white">
<UpperSection /> <UpperSection />
<BottomSection /> <BottomSection />
</div> </div>

@ -25,19 +25,19 @@ type ProfileOffersProps = Readonly<{
}>; }>;
function ProfileOffers({ offers }: ProfileOffersProps) { function ProfileOffers({ offers }: ProfileOffersProps) {
if (offers.length !== 0) { if (offers.length === 0) {
return ( return (
<> <div className="p-4">
{offers.map((offer) => ( <p className="font-semibold">No offers are attached.</p>
<OfferCard key={offer.id} offer={offer} /> </div>
))}
</>
); );
} }
return ( return (
<div className="mx-8 my-4 flex flex-row"> <div className="space-y-4 p-4">
<BriefcaseIcon className="mr-1 h-5" /> {offers.map((offer) => (
<span className="font-bold">No offer is attached.</span> <OfferCard key={offer.id} offer={offer} />
))}
</div> </div>
); );
} }
@ -49,33 +49,37 @@ type ProfileBackgroundProps = Readonly<{
function ProfileBackground({ background }: ProfileBackgroundProps) { function ProfileBackground({ background }: ProfileBackgroundProps) {
if (!background?.experiences?.length && !background?.educations?.length) { if (!background?.experiences?.length && !background?.educations?.length) {
return ( return (
<div className="mx-8 my-4"> <div className="p-4">
<p>No background information available.</p> <p>No background information available.</p>
</div> </div>
); );
} }
return ( return (
<> <div className="space-y-8 p-4">
{background?.experiences?.length > 0 && ( {background?.experiences?.length > 0 && (
<> <div className="space-y-2">
<div className="mx-8 my-4 flex flex-row"> <div className="flex items-center space-x-2 text-slate-500">
<BriefcaseIcon className="mr-1 h-5" /> <BriefcaseIcon className="h-5" />
<span className="font-bold">Work Experience</span> <h3 className="text-sm font-semibold uppercase tracking-wide">
Work Experience
</h3>
</div> </div>
<OfferCard offer={background.experiences[0]} /> <OfferCard offer={background.experiences[0]} />
</> </div>
)} )}
{background?.educations?.length > 0 && ( {background?.educations?.length > 0 && (
<> <div className="space-y-2">
<div className="mx-8 my-4 flex flex-row"> <div className="flex items-center space-x-2 text-slate-500">
<AcademicCapIcon className="mr-1 h-5" /> <AcademicCapIcon className="h-5" />
<span className="font-bold">Education</span> <h3 className="text-sm font-semibold uppercase tracking-wide">
Education
</h3>
</div> </div>
<EducationCard education={background.educations[0]} /> <EducationCard education={background.educations[0]} />
</> </div>
)} )}
</> </div>
); );
} }
@ -114,7 +118,7 @@ function ProfileAnalysis({
} }
return ( return (
<div className="mx-8 my-4"> <div className="p-4">
{!analysis ? ( {!analysis ? (
<p>No analysis available.</p> <p>No analysis available.</p>
) : ( ) : (
@ -165,12 +169,15 @@ export default function ProfileDetails({
</div> </div>
); );
} }
if (selectedTab === ProfileDetailTab.OFFERS) { if (selectedTab === ProfileDetailTab.OFFERS) {
return <ProfileOffers offers={offers} />; return <ProfileOffers offers={offers} />;
} }
if (selectedTab === ProfileDetailTab.BACKGROUND) { if (selectedTab === ProfileDetailTab.BACKGROUND) {
return <ProfileBackground background={background} />; return <ProfileBackground background={background} />;
} }
if (selectedTab === ProfileDetailTab.ANALYSIS) { if (selectedTab === ProfileDetailTab.ANALYSIS) {
return ( return (
<ProfileAnalysis <ProfileAnalysis

@ -233,20 +233,20 @@ export default function ProfileHeader({
const { experiences, totalYoe, specificYoes, profileName } = background; const { experiences, totalYoe, specificYoes, profileName } = background;
return ( return (
<div className="grid-rows-2 bg-white p-4"> <div className="grid-rows-2 bg-white">
<div className="flex grid grid-cols-5 md:grid-cols-7"> <div className="grid grid-cols-5 p-4 md:grid-cols-7">
<div className="jsutify-start col-span-5 flex"> <div className="col-span-5 flex justify-start space-x-4">
<div className="ml-0 mr-2 mt-2 h-16 w-16 md:mx-4"> <div className="mt-2 h-16 w-16">
<ProfilePhotoHolder /> <ProfilePhotoHolder />
</div> </div>
<div> <div className="space-y-1">
<h2 className="flex text-2xl font-bold"> <h2 className="flex text-2xl font-bold">
{profileName ?? 'anonymous'} {profileName ?? 'anonymous'}
</h2> </h2>
{(experiences[0]?.companyName || {(experiences[0]?.companyName ||
experiences[0]?.jobLevel || experiences[0]?.jobLevel ||
experiences[0]?.jobTitle) && ( experiences[0]?.jobTitle) && (
<div className="flex flex-row text-slate-600"> <div className="flex items-center text-sm text-slate-600">
<span> <span>
<BuildingOffice2Icon className="mr-2.5 h-5 w-5" /> <BuildingOffice2Icon className="mr-2.5 h-5 w-5" />
</span> </span>
@ -262,7 +262,7 @@ export default function ProfileHeader({
</p> </p>
</div> </div>
)} )}
<div className="flex flex-row text-slate-600"> <div className="flex items-center text-sm text-slate-600">
<CalendarDaysIcon className="mr-2.5 h-5" /> <CalendarDaysIcon className="mr-2.5 h-5" />
<p> <p>
<span className="mr-2 font-bold">YOE:</span> <span className="mr-2 font-bold">YOE:</span>
@ -286,7 +286,7 @@ export default function ProfileHeader({
</div> </div>
)} )}
</div> </div>
<div className="mt-4"> <div className="border-t border-slate-200 p-4">
<Tabs <Tabs
label="Profile Detail Navigation" label="Profile Detail Navigation"
tabs={profileDetailTabs} tabs={profileDetailTabs}

@ -215,7 +215,7 @@ export default function OfferProfile() {
setSelectedTab={setSelectedTab} setSelectedTab={setSelectedTab}
/> />
</div> </div>
<div className="pb-4"> <div>
<ProfileDetails <ProfileDetails
analysis={analysis} analysis={analysis}
background={background} background={background}

@ -4,11 +4,11 @@ import { JobTypeLabel } from '~/components/offers/constants';
import type { Location } from '~/types/offers'; import type { Location } from '~/types/offers';
function joinWithComma(...strings: Array<string | null | undefined>) { export function joinWithComma(...strings: Array<string | null | undefined>) {
return strings.filter((value) => !!value).join(', '); return strings.filter((value) => !!value).join(', ');
} }
function getLocationDisplayText({ cityName, countryName }: Location) { export function getLocationDisplayText({ cityName, countryName }: Location) {
return cityName === countryName return cityName === countryName
? cityName ? cityName
: joinWithComma(cityName, countryName); : joinWithComma(cityName, countryName);

Loading…
Cancel
Save