[offers][feat] show company logo

pull/555/head
Yangshun Tay 2 years ago
parent c6941c0a5a
commit ada6a68420

@ -6,6 +6,7 @@ import {
import { JobType } from '@prisma/client';
import { JobTypeLabel } from '~/components/offers/constants';
import CompanyProfileImage from '~/components/shared/CompanyProfileImage';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@ -31,8 +32,13 @@ export default function DashboardProfileCard({
}: Props) {
return (
<div className="px-4 py-4 sm:px-6">
<div className="flex items-end justify-between">
<div className="col-span-1 row-span-3">
<div className="flex justify-between gap-4">
<CompanyProfileImage
alt={company.name}
className="hidden h-10 w-10 object-contain sm:block"
src={company.logoUrl}
/>
<div className="grow">
<h4 className="font-medium">
{getLabelForJobTitleType(title as JobTitleType)}{' '}
{jobType && <>({JobTypeLabel[jobType]})</>}

@ -10,6 +10,7 @@ import {
} from '@heroicons/react/24/outline';
import { JobType } from '@prisma/client';
import CompanyProfileImage from '~/components/shared/CompanyProfileImage';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@ -89,8 +90,13 @@ export default function OfferProfileCard({
function BottomSection() {
return (
<div className="px-4 py-4 sm:px-6">
<div className="flex items-end justify-between">
<div className="col-span-1 row-span-3">
<div className="flex justify-between gap-4">
<CompanyProfileImage
alt={company.name}
className="hidden h-10 w-10 object-contain sm:block"
src={company.logoUrl}
/>
<div className="grow">
<h4 className="font-medium">
{getLabelForJobTitleType(title as JobTitleType)}{' '}
{jobType && <>({JobTypeLabel[jobType]})</>}
@ -125,7 +131,7 @@ export default function OfferProfileCard({
)}
</div>
</div>
<div className="col-span-1 row-span-3">
<div className="flex flex-col justify-center">
<p className="text-end text-lg font-medium leading-6 text-slate-900">
{jobType === JobType.FULLTIME
? `${convertMoneyToString(income)} / year`

@ -9,6 +9,7 @@ import { JobType } from '@prisma/client';
import { JobTypeLabel } from '~/components/offers/constants';
import { InternshipCycleValuesToLabels } from '~/components/offers/InternshipCycles';
import type { OfferDisplayData } from '~/components/offers/types';
import CompanyProfileImage from '~/components/shared/CompanyProfileImage';
import { getLocationDisplayText } from '~/utils/offers/string';
import { getDurationDisplayText } from '~/utils/offers/time';
@ -21,7 +22,7 @@ export default function OfferCard({
offer: {
base,
bonus,
companyName,
company,
duration,
internshipCycle,
jobTitle,
@ -40,19 +41,26 @@ export default function OfferCard({
function UpperSection() {
return (
<div className="px-4 py-5 sm:px-6">
<div className="flex justify-between">
<div>
<div className="flex justify-between gap-4">
{company && (
<CompanyProfileImage
alt={company.name}
className="h-10 w-10 object-contain"
src={company.logoUrl}
/>
)}
<div className="grow">
<h3 className="text-lg font-medium leading-6 text-slate-900">
{jobTitle} {jobType && <>({JobTypeLabel[jobType]})</>}
</h3>
<div className="mt-1 flex flex-row flex-wrap sm:mt-0">
{companyName && (
{company?.name != null && (
<div className="mr-4 mt-2 flex items-center text-sm text-slate-500">
<BuildingOfficeIcon
aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-slate-400"
/>
{companyName}
{company?.name}
</div>
)}
{location && (

@ -34,11 +34,22 @@ function ProfileOffers({ offers }: ProfileOffersProps) {
}
return (
<div className="space-y-4 p-4">
<div className="p-4">
<div className="space-y-4">
{offers.map((offer) => (
<OfferCard key={offer.id} offer={offer} />
))}
</div>
<div className="mt-1 text-end">
<a
className="text-xs text-slate-500"
href="https://clearbit.com"
rel="noreferrer"
target="_blank">
Logos provided by Clearbit
</a>
</div>
</div>
);
}
@ -140,6 +151,15 @@ function ProfileAnalysis({
/>
</div>
)}
<div className="text-end">
<a
className="text-xs text-slate-500"
href="https://clearbit.com"
rel="noreferrer"
target="_blank">
Logos provided by Clearbit
</a>
</div>
</div>
);
}
@ -188,5 +208,6 @@ export default function ProfileDetails({
/>
);
}
return null;
}

@ -243,7 +243,7 @@ export default function ProfileHeader({
<h2 className="flex text-2xl font-bold">
{profileName ?? 'anonymous'}
</h2>
{(experiences[0]?.companyName ||
{(experiences[0]?.company?.name ||
experiences[0]?.jobLevel ||
experiences[0]?.jobTitle) && (
<div className="flex items-center text-sm text-slate-600">
@ -252,7 +252,7 @@ export default function ProfileHeader({
</span>
<p>
<span className="mr-2 font-bold">Current:</span>
{`${experiences[0].companyName || ''} ${
{`${experiences[0].company?.name || ''} ${
experiences[0].jobLevel || ''
} ${experiences[0].jobTitle || ''} ${
experiences[0].jobType

@ -2,6 +2,7 @@ import clsx from 'clsx';
import Link from 'next/link';
import { JobType } from '@prisma/client';
import CompanyProfileImage from '~/components/shared/CompanyProfileImage';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
@ -34,11 +35,20 @@ export default function OfferTableRow({
}: OfferTableRowProps) {
return (
<tr key={id} className="divide-x divide-slate-200 border-b bg-white">
<td className="space-y-0.5 py-2 px-4" scope="row">
<div className="font-medium">{company.name}</div>
<td className="flex items-center gap-3 space-y-0.5 py-2 px-4" scope="row">
<CompanyProfileImage
alt={company.name}
className="hidden h-6 w-6 object-contain sm:block"
src={company.logoUrl}
/>
<div>
<div className="line-clamp-2 sm:line-clamp-1 font-medium">
{company.name}
</div>
<div className="text-xs text-slate-500">
{location.cityName} ({location.countryCode})
</div>
</div>
</td>
<td className="py-2 px-4">
{getLabelForJobTitleType(title as JobTitleType)}

@ -2,6 +2,8 @@ import type { JobType } from '@prisma/client';
import type { MonthYear } from '~/components/shared/MonthYearPicker';
import type { OffersCompany } from '../../types/offers';
import type { Location } from '~/types/offers';
/**
@ -177,7 +179,7 @@ export type EducationDisplayData = {
export type OfferDisplayData = {
base?: string | null;
bonus?: string | null;
companyName?: string | null;
company?: OffersCompany | null;
duration?: number | null;
id?: string;
internshipCycle?: string;

@ -0,0 +1,31 @@
import clsx from 'clsx';
import { useState } from 'react';
import { BuildingOffice2Icon } from '@heroicons/react/24/outline';
type Props = Readonly<{
alt: string;
className: string;
src: string;
}>;
export default function CompanyProfileImage({ alt, className, src }: Props) {
const [hasError, setHasError] = useState(false);
return hasError ? (
<div
className={clsx(
'shrink-0 rounded bg-slate-50 p-0.5 text-slate-400',
className,
)}>
<BuildingOffice2Icon />
</div>
) : (
<img
alt={alt}
className={clsx('object-contain', className)}
src={src}
onError={() => {
setHasError(true);
}}
/>
);
}

@ -85,13 +85,13 @@ export default function ProfilesDashboard() {
{!userProfilesQuery.isLoading && (
<div className="overflow-y-auto py-8">
<h1 className="mx-auto mb-4 text-start text-4xl font-bold text-slate-900">
My dashboard
Dashboard
</h1>
<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.
Save offer profiles to your dashboard to easily access and edit
them later.
</p>
<div className="mt-8 flex justify-center">
<div className="mt-8">
<ul className="w-full space-y-4" role="list">
{userProfiles?.map((profile) => (
<li key={profile.id}>
@ -99,6 +99,15 @@ export default function ProfilesDashboard() {
</li>
))}
</ul>
<div className="mt-2 text-end">
<a
className="text-xs text-slate-500"
href="https://clearbit.com"
rel="noreferrer"
target="_blank">
Logos provided by Clearbit
</a>
</div>
</div>
</div>
)}

@ -186,6 +186,15 @@ export default function OffersHomePage({
selectedSortType={selectedSortType}
onSort={onSort}
/>
<div className="mt-1 text-end">
<a
className="text-xs text-slate-500"
href="https://clearbit.com"
rel="noreferrer"
target="_blank">
Logos provided by Clearbit
</a>
</div>
</Container>
</main>
</>

@ -74,7 +74,7 @@ export default function OfferProfile() {
res.offersFullTime.bonus != null
? convertMoneyToString(res.offersFullTime.bonus)
: undefined,
companyName: res.company.name,
company: res.company,
id: res.offersFullTime.id,
jobLevel: res.offersFullTime.level,
jobTitle: getLabelForJobTitleType(
@ -96,7 +96,7 @@ export default function OfferProfile() {
return filteredOffer;
}
const filteredOffer: OfferDisplayData = {
companyName: res.company.name,
company: res.company,
id: res.offersIntern!.id,
internshipCycle: res.offersIntern!.internshipCycle,
jobTitle: getLabelForJobTitleType(
@ -130,7 +130,7 @@ export default function OfferProfile() {
})),
experiences: data.background.experiences.map(
(experience): OfferDisplayData => ({
companyName: experience.company?.name,
company: experience.company,
duration: experience.durationInMonths,
jobLevel: experience.level,
jobTitle: experience.title
@ -197,10 +197,10 @@ export default function OfferProfile() {
<Error statusCode={404} title="Requested profile does not exist." />
</div>
) : getProfileQuery.isLoading ? (
<div className="flex h-screen w-screen">
<div className="m-auto mx-auto w-screen justify-center font-medium text-slate-500">
<div className="flex h-screen w-full items-center justify-center text-slate-500">
<div className="flex flex-col gap-2">
<Spinner display="block" size="lg" />
<div className="text-center">Loading profile...</div>
<p className="text-center">Loading profile...</p>
</div>
</div>
) : (

@ -141,6 +141,15 @@ export default function OffersSubmissionResult() {
</div>
)}
</div>
<div className="px-6 py-2 text-end sm:px-10">
<a
className="text-xs text-slate-500"
href="https://clearbit.com"
rel="noreferrer"
target="_blank">
Logos provided by Clearbit
</a>
</div>
</div>
</div>
</div>

Loading…
Cancel
Save