[offers] tweak offer profiles UI

pull/492/head
Yangshun Tay 2 years ago
parent 8e08ff86f4
commit ea57743cfe

@ -1,5 +1,9 @@
import {
ArrowTrendingUpIcon,
BuildingOfficeIcon,
MapPinIcon,
} from '@heroicons/react/20/solid';
import { JobType } from '@prisma/client';
import { HorizontalDivider } from '@tih/ui';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@ -10,12 +14,10 @@ import { formatDate } from '~/utils/offers/time';
import type { UserProfileOffer } from '~/types/offers';
type Props = Readonly<{
disableTopDivider?: boolean;
offer: UserProfileOffer;
}>;
export default function DashboardProfileCard({
disableTopDivider,
offer: {
company,
income,
@ -27,29 +29,53 @@ export default function DashboardProfileCard({
},
}: Props) {
return (
<>
{!disableTopDivider && <HorizontalDivider />}
<div className="px-4 py-4 sm:px-6">
<div className="flex items-end justify-between">
<div className="col-span-1 row-span-3">
<p className="font-bold">
<h4 className="font-medium">
{getLabelForJobTitleType(title as JobTitleType)}
</p>
<p>
{location
? `Company: ${company.name}, ${location}`
: `Company: ${company.name}`}
</p>
{level && <p>Level: {level}</p>}
</h4>
<div className="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-4">
{company?.name && (
<div className="mt-2 flex items-center text-sm text-gray-500">
<BuildingOfficeIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
/>
{company.name}
</div>
)}
{location && (
<div className="mt-2 flex items-center text-sm text-gray-500">
<MapPinIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
/>
{location}
</div>
)}
{level && (
<div className="mt-2 flex items-center text-sm text-gray-500">
<ArrowTrendingUpIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
/>
{level}
</div>
)}
</div>
</div>
<div className="col-span-1 row-span-3">
<p className="text-end">{formatDate(monthYearReceived)}</p>
<p className="text-end text-xl">
<p className="text-end text-lg font-medium leading-6 text-slate-900">
{jobType === JobType.FULLTIME
? `${convertMoneyToString(income)} / year`
: `${convertMoneyToString(income)} / month`}
</p>
<p className="text-end text-sm text-slate-500">
{formatDate(monthYearReceived)}
</p>
</div>
</div>
</>
</div>
);
}

@ -1,5 +1,6 @@
import { useRouter } from 'next/router';
import { ArrowRightIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { BookmarkSlashIcon } from '@heroicons/react/20/solid';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { Button, useToast } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
@ -43,54 +44,52 @@ export default function DashboardProfileCard({
);
function handleRemoveProfile() {
// TODO(offers): Confirm before removal.
removeSavedProfileMutation.mutate({ profileId: id });
}
return (
<div className="space-y-4 bg-white px-4 pt-5 sm:px-4">
<div className="overflow-hidden bg-white sm:rounded-lg sm:shadow">
{/* Header */}
<div className="-ml-4 -mt-2 flex flex-wrap items-center justify-between border-b border-gray-300 pb-4 sm:flex-nowrap">
<div className="flex items-center gap-x-5">
<div>
<ProfilePhotoHolder size="sm" />
</div>
<div className="col-span-10">
<p className="text-xl font-bold">{profileName}</p>
<div className="flex flex-row">
<span>Created at {formatDate(createdAt)}</span>
<div className="border-b border-slate-200 bg-white px-4 py-5 sm:px-6">
<div className="-ml-4 -mt-4 flex flex-wrap items-center justify-between sm:flex-nowrap">
<div className="ml-4 mt-4">
<div className="flex items-center">
<div className="flex-shrink-0">
<ProfilePhotoHolder size="sm" />
</div>
<div className="ml-4">
<h2 className="text-lg font-medium leading-6 text-slate-900">
{profileName}
</h2>
<p className="text-sm text-slate-500">
<span>Created at {formatDate(createdAt)}</span>
</p>
</div>
</div>
</div>
</div>
<div className="flex self-start">
<Button
disabled={removeSavedProfileMutation.isLoading}
icon={XMarkIcon}
isLabelHidden={true}
label="Remove Profile"
size="md"
variant="tertiary"
onClick={handleRemoveProfile}
/>
</div>
</div>
{/* Offers */}
<div>
{offers.map((offer: UserProfileOffer, index) =>
index === 0 ? (
<DashboardOfferCard
key={offer.id}
disableTopDivider={true}
offer={offer}
<div className="ml-4 mt-4 flex flex-shrink-0">
<Button
disabled={removeSavedProfileMutation.isLoading}
icon={BookmarkSlashIcon}
isLabelHidden={true}
label="Remove Profile"
size="md"
variant="tertiary"
onClick={handleRemoveProfile}
/>
) : (
<DashboardOfferCard key={offer.id} offer={offer} />
),
)}
</div>
</div>
</div>
<div className="flex justify-end pt-1">
{/* List of Offers */}
<ul className="divide-y divide-slate-200" role="list">
{offers.map((offer: UserProfileOffer) => (
<li key={offer.id}>
<DashboardOfferCard offer={offer} />
</li>
))}
</ul>
<div className="flex justify-end border-t border-slate-200 px-4 py-5 sm:px-6">
<Button
disabled={removeSavedProfileMutation.isLoading}
icon={ArrowRightIcon}

@ -1,7 +1,8 @@
import { signIn, useSession } from 'next-auth/react';
import { useState } from 'react';
import { DocumentDuplicateIcon } from '@heroicons/react/20/solid';
import { BookmarkSquareIcon, CheckIcon } from '@heroicons/react/24/outline';
import { BookmarkIcon as BookmarkOutlineIcon } from '@heroicons/react/24/outline';
import { BookmarkIcon as BookmarkSolidIcon } from '@heroicons/react/24/solid';
import { Button, TextInput, useToast } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
@ -126,7 +127,7 @@ export default function OffersProfileSave({
<div className="mt-6">
<Button
disabled={isSavedQuery.isLoading || isSaved}
icon={isSaved ? CheckIcon : BookmarkSquareIcon}
icon={isSaved ? BookmarkSolidIcon : BookmarkOutlineIcon}
isLoading={saveMutation.isLoading || isSavedQuery.isLoading}
label={isSaved ? 'Added to account' : 'Add to your account'}
size="sm"

@ -264,7 +264,7 @@ export default function OffersSubmissionForm({
}, []);
return (
<div ref={pageRef} className="w-full overflow-y-scroll">
<div ref={pageRef} className="w-full">
<div className="flex justify-center">
<div className="block w-full max-w-screen-md overflow-hidden rounded-lg sm:shadow-lg md:my-10">
<div className="flex justify-center bg-slate-100 px-4 py-4 sm:px-6 lg:px-8">

@ -110,10 +110,10 @@ export default function ProfileComments({
);
}
return (
<div className="bh-white h-fit px-4 md:h-[calc(100vh-4.5rem)] md:overflow-y-auto">
<div className="bg-white pt-4 md:sticky md:top-0">
<div className="bh-white h-fit px-4 lg:h-[calc(100vh-4.5rem)] lg:overflow-y-auto">
<div className="bg-white pt-4 lg:sticky lg:top-0">
<div className="flex justify-end">
<div className="grid w-fit space-y-2 md:grid-cols-1 lg:grid-cols-2 lg:space-y-0 lg:space-x-4">
<div className="grid w-fit space-y-2 lg:grid-cols-1 lg:grid-cols-2 lg:space-y-0 lg:space-x-4">
<div className="col-span-1 flex justify-end">
{isEditable && (
<Tooltip tooltipContent="Copy this link to edit your profile later">
@ -210,7 +210,7 @@ export default function ProfileComments({
/>
)}
</div>
<div className="h-full w-full">
<div className="w-full">
{replies?.map((reply: Reply) => (
<ExpandableCommentCard
key={reply.id}

@ -1,6 +1,6 @@
type ProfilePhotoHolderProps = {
type ProfilePhotoHolderProps = Readonly<{
size?: 'lg' | 'sm';
};
}>;
export default function ProfilePhotoHolder({
size = 'lg',

@ -4,20 +4,21 @@ import React from 'react';
type Props = Readonly<{
children: React.ReactNode;
className?: string;
variant?: 'narrow' | 'normal';
variant?: 'md' | 'sm' | 'xs';
}>;
export default function Container({
children,
className,
variant = 'normal',
variant = 'md',
}: Props) {
return (
<div
className={clsx(
'mx-auto px-4 sm:px-6 lg:px-8',
variant === 'normal' && 'max-w-7xl',
variant === 'narrow' && 'max-w-6xl',
variant === 'md' && 'max-w-7xl',
variant === 'sm' && 'max-w-5xl',
variant === 'xs' && 'max-w-3xl',
className,
)}>
{children}

@ -4,6 +4,7 @@ import { useState } from 'react';
import { Button, Spinner } from '@tih/ui';
import DashboardProfileCard from '~/components/offers/dashboard/DashboardProfileCard';
import Container from '~/components/shared/Container';
import { trpc } from '~/utils/trpc';
@ -30,19 +31,21 @@ export default function ProfilesDashboard() {
if (status === 'loading' || userProfilesQuery.isLoading) {
return (
<div className="flex h-screen w-screen">
<div className="flex w-full">
<div className="m-auto mx-auto w-full justify-center">
<Spinner className="m-10" display="block" size="lg" />
</div>
</div>
);
}
if (status === 'unauthenticated') {
signIn();
}
if (userProfiles.length === 0) {
return (
<div className="flex h-screen w-screen">
<div className="flex w-full">
<div className="m-auto mx-auto w-full justify-center text-xl">
<div className="mb-8 flex w-full flex-row justify-center">
<h2>You have not saved any offer profiles yet.</h2>
@ -59,10 +62,11 @@ export default function ProfilesDashboard() {
</div>
);
}
return (
<>
<Container variant="xs">
{userProfilesQuery.isLoading && (
<div className="flex h-screen w-screen">
<div className="flex h-screen">
<div className="m-auto mx-auto w-full justify-center">
<Spinner className="m-10" display="block" size="lg" />
</div>
@ -70,19 +74,17 @@ export default function ProfilesDashboard() {
)}
{!userProfilesQuery.isLoading && (
<div className="overflow-y-auto py-8">
<h1 className="mx-auto mb-4 w-3/4 text-start text-4xl font-bold text-slate-900">
<h1 className="mx-auto mb-4 text-start text-4xl font-bold text-slate-900">
Your dashboard
</h1>
<p className="mx-auto w-3/4 text-start text-xl text-slate-900">
Save your offer profiles to dashboard to easily access and edit them
later.
<p className="mt-4 text-xl leading-8 text-slate-500">
Save your offer profiles to your dashboard to easily access and edit
them later.
</p>
<div className="justfy-center mt-8 flex w-screen">
<ul className="mx-auto w-3/4 space-y-3" role="list">
<div className="mt-8 flex justify-center">
<ul className="w-full space-y-4" role="list">
{userProfiles?.map((profile) => (
<li
key={profile.id}
className="overflow-hidden bg-white px-4 py-4 shadow sm:rounded-md sm:px-6">
<li key={profile.id}>
<DashboardProfileCard key={profile.id} profile={profile} />
</li>
))}
@ -90,6 +92,6 @@ export default function ProfilesDashboard() {
</div>
</div>
)}
</>
</Container>
);
}

@ -202,9 +202,9 @@ export default function OfferProfile() {
</div>
)}
{!getProfileQuery.isLoading && !getProfileQuery.isError && (
<div className="h-fuill flex grid w-full grid-cols-1 items-center justify-center divide-x overflow-y-auto md:grid-cols-3">
<div className="col-span-1 flex h-full flex-col divide-y md:col-span-2 md:overflow-y-auto">
<div className="h-fit md:sticky md:top-0">
<div className="w-full divide-x lg:flex">
<div className="divide-y lg:w-2/3">
<div className="h-fit">
<ProfileHeader
background={background}
handleDelete={handleDelete}
@ -226,7 +226,9 @@ export default function OfferProfile() {
/>
</div>
</div>
<div className="col-span-1 h-full bg-white">
<div
className="bg-white lg:fixed lg:right-0 lg:bottom-0 lg:w-1/3"
style={{ top: 64 }}>
<ProfileComments
isDisabled={deleteMutation.isLoading}
isEditable={isEditable}

@ -78,7 +78,7 @@ export default function OffersSubmissionResult() {
</div>
)}
{!getAnalysis.isLoading && (
<div ref={pageRef} className="w-full overflow-y-scroll">
<div ref={pageRef} className="w-full">
<div className="flex justify-center">
<div className="block w-full max-w-screen-md overflow-hidden rounded-lg sm:shadow-lg md:my-10">
<div className="flex justify-center bg-slate-100 px-4 py-4 sm:px-6 lg:px-8">

Loading…
Cancel
Save