From 6a303c6e73f3f0b6efaee2b0a15e29e1e5999fa0 Mon Sep 17 00:00:00 2001 From: Ido Shamun Date: Sun, 18 Jan 2026 13:49:39 +0200 Subject: [PATCH] refactor: update recruiter logo and analyze page --- packages/shared/src/components/Logo.tsx | 12 +- .../components/recruiter/AnalyzeStatusBar.tsx | 6 +- .../src/components/recruiter/Header.tsx | 4 +- .../components/analyze/AnalyzeContent.tsx | 77 ------------- .../components/analyze/JobInfo.tsx | 107 +++++++++++++----- .../components/analyze/ReachHeroSection.tsx | 17 +-- packages/shared/src/svg/LogoRecruiterSvg.tsx | 66 ----------- 7 files changed, 96 insertions(+), 193 deletions(-) delete mode 100644 packages/shared/src/svg/LogoRecruiterSvg.tsx diff --git a/packages/shared/src/components/Logo.tsx b/packages/shared/src/components/Logo.tsx index 9300a03418..b41f43097d 100644 --- a/packages/shared/src/components/Logo.tsx +++ b/packages/shared/src/components/Logo.tsx @@ -19,12 +19,6 @@ const DevPlusIcon = dynamic(() => ), ); -const LogoRecruiterSvg = dynamic(() => - import( - /* webpackChunkName: "logoRecruiterSvg" */ '../svg/LogoRecruiterSvg' - ).then((mod) => mod.LogoRecruiterSvg), -); - export enum LogoPosition { Absolute = 'absolute', Relative = 'relative', @@ -152,7 +146,11 @@ export default function Logo({ fallback={LogoText} /> )} - {isRecruiter && !compact && } + {isRecruiter && !compact && ( + + Recruiter + + )} ); diff --git a/packages/shared/src/components/recruiter/AnalyzeStatusBar.tsx b/packages/shared/src/components/recruiter/AnalyzeStatusBar.tsx index 79457b7c85..77f256e157 100644 --- a/packages/shared/src/components/recruiter/AnalyzeStatusBar.tsx +++ b/packages/shared/src/components/recruiter/AnalyzeStatusBar.tsx @@ -12,11 +12,11 @@ import { IconSize } from '../Icon'; const LOADING_STEPS = [ 'Analyzing your job description (this may take a minute)', - 'Mapping skills, requirements, and intent', - 'Scanning the daily.dev network...', + 'Extracting skills and requirements', + 'Finding matches in our community...', ]; -const COMPLETE_MESSAGE = 'Your hiring edge is ready'; +const COMPLETE_MESSAGE = 'Your analysis is ready'; type AnalyzeStatusBarProps = { loadingStep: number; diff --git a/packages/shared/src/components/recruiter/Header.tsx b/packages/shared/src/components/recruiter/Header.tsx index a7a82458b9..c42eedd8c3 100644 --- a/packages/shared/src/components/recruiter/Header.tsx +++ b/packages/shared/src/components/recruiter/Header.tsx @@ -24,8 +24,8 @@ export interface RecruiterHeaderProps { } export const RecruiterHeader = ({ - title = 'Your potential reach', - subtitle = "See how many developers match your role and what they're interested in.", + title = 'Reach analysis', + subtitle = 'See who in our community fits your role', headerButton, }: RecruiterHeaderProps) => { return ( diff --git a/packages/shared/src/features/opportunity/components/analyze/AnalyzeContent.tsx b/packages/shared/src/features/opportunity/components/analyze/AnalyzeContent.tsx index 4e5431f175..02741a3b4a 100644 --- a/packages/shared/src/features/opportunity/components/analyze/AnalyzeContent.tsx +++ b/packages/shared/src/features/opportunity/components/analyze/AnalyzeContent.tsx @@ -7,10 +7,7 @@ import { import { useOpportunityPreviewContext } from '../../context/OpportunityPreviewContext'; import { OpportunityPreviewStatus } from '../../types'; import { JobInfo } from './JobInfo'; -import { apiUrl } from '../../../../lib/config'; import { ReachHeroSection } from './ReachHeroSection'; -import { InsightCard } from './InsightCard'; -import { Chip } from '../../../../components/cards/common/PostTags'; import { PlusUserIcon } from '../../../../components/icons/PlusUser'; import { IconSize } from '../../../../components/Icon'; @@ -18,21 +15,12 @@ type AnalyzeContentProps = { loadingStep: number; }; -const iconSize = 24; - export const AnalyzeContent = ({ loadingStep }: AnalyzeContentProps) => { const data = useOpportunityPreviewContext(); const isReady = data?.result?.status === OpportunityPreviewStatus.READY; const totalCount = data?.result?.totalCount ?? 0; - const tags = data?.result?.tags ?? []; - const companies = data?.result?.companies ?? []; - - // Mock engagement stat - in production this would come from the API - const avgTimePerWeek = '4.2 hrs'; const isError = data?.result?.status === OpportunityPreviewStatus.ERROR; - const showAggregation = - !isError && loadingStep >= 2 && (isReady || tags.length > 0); const showReachHero = !isError && loadingStep >= 2; return ( @@ -60,71 +48,6 @@ export const AnalyzeContent = ({ loadingStep }: AnalyzeContentProps) => { )} - {/* Candidate Insights */} - {showAggregation && ( -
- {/* Tags */} - -
- {tags.map((tag) => ( - - #{tag} - - ))} -
-
- - {/* Companies */} - -
- {companies.slice(0, 4).map((company) => ( - - {company.name} - {company.name} - - ))} -
-
- - {/* Platform Engagement */} - -
- - {avgTimePerWeek} - - - avg. per candidate - -
-
-
- )} - {/* Job Summary */}
= { + [LocationType.UNSPECIFIED]: null, + [LocationType.REMOTE]: 'Remote', + [LocationType.OFFICE]: 'On-site', + [LocationType.HYBRID]: 'Hybrid', +}; + +const salaryPeriodMap: Record = { + [SalaryPeriod.UNSPECIFIED]: 'year', + [SalaryPeriod.ANNUAL]: 'year', + [SalaryPeriod.MONTHLY]: 'month', + [SalaryPeriod.WEEKLY]: 'week', + [SalaryPeriod.DAILY]: 'day', + [SalaryPeriod.HOURLY]: 'hour', +}; + +const formatSalary = (salary?: Salary): string | null => { + if (!salary?.min || !salary?.max) { + return null; + } + const min = salary.min / 1000; + const max = salary.max / 1000; + const period = salaryPeriodMap[salary.period ?? SalaryPeriod.UNSPECIFIED]; + return `$${min}k - $${max}k/${period}`; +}; type JobInfoProps = { loadingStep: number; @@ -33,8 +61,10 @@ export const JobInfo = ({ loadingStep }: JobInfoProps) => { ); } + const { locations, meta, title, tldr, keywords } = opportunity; + const locationString = - opportunity.locations + locations ?.map((item) => [ item.location?.city, @@ -44,51 +74,68 @@ export const JobInfo = ({ loadingStep }: JobInfoProps) => { .filter(Boolean) .join(', '), ) - .join(' · ') || 'Location not specified'; + .join(' · ') || null; const seniorityLabel = - seniorityLevelMap[ - opportunity.meta?.seniorityLevel ?? SeniorityLevel.UNSPECIFIED - ]; + seniorityLevelMap[meta?.seniorityLevel ?? SeniorityLevel.UNSPECIFIED]; + + const workArrangement = + locationTypeMap[locations?.[0]?.type ?? LocationType.UNSPECIFIED]; + + const salaryRange = formatSalary(meta?.salary); + + // Build meta items array for clean rendering + const metaItems = [ + locationString, + seniorityLabel !== 'N/A' ? seniorityLabel : null, + workArrangement, + salaryRange, + ].filter(Boolean); return (
{/* Title and meta */}
- {opportunity.title} + {title} -
- - {locationString} - - {seniorityLabel && ( - <> - · - - {seniorityLabel} - - - )} -
+ {metaItems.length > 0 && ( +
+ {metaItems.map((item, index) => ( + + {index > 0 && ·} + + {item} + + + ))} +
+ )}
+ {/* TLDR */} + {tldr && ( + + TLDR {tldr} + + )} + {/* Tech stack */} - {opportunity.keywords && opportunity.keywords.length > 0 && ( + {keywords && keywords.length > 0 && (
- {opportunity.keywords.slice(0, 10).map((tag) => ( + {keywords.slice(0, 10).map((tag) => ( #{tag.keyword} ))} - {opportunity.keywords.length > 10 && ( - +{opportunity.keywords.length - 10} + {keywords.length > 10 && ( + +{keywords.length - 10} )}
)} diff --git a/packages/shared/src/features/opportunity/components/analyze/ReachHeroSection.tsx b/packages/shared/src/features/opportunity/components/analyze/ReachHeroSection.tsx index 532357ed27..58bd2d199c 100644 --- a/packages/shared/src/features/opportunity/components/analyze/ReachHeroSection.tsx +++ b/packages/shared/src/features/opportunity/components/analyze/ReachHeroSection.tsx @@ -11,8 +11,6 @@ type ReachHeroSectionProps = { isLoading: boolean; }; -const PASSIVE_PERCENTAGE = 30; - export const ReachHeroSection = ({ totalCount, isLoading, @@ -58,6 +56,13 @@ export const ReachHeroSection = ({ return (
+ {/* Label */} + + Potential reach + {/* Hero number */} {animatedCount.toLocaleString()} @@ -65,22 +70,18 @@ export const ReachHeroSection = ({ developers matched - {/* Exclusive stat */} + {/* Community differentiator */}
- - {PASSIVE_PERCENTAGE}% - {' '} - are passively open to new opportunities + Active in our community
diff --git a/packages/shared/src/svg/LogoRecruiterSvg.tsx b/packages/shared/src/svg/LogoRecruiterSvg.tsx deleted file mode 100644 index 0493e59b39..0000000000 --- a/packages/shared/src/svg/LogoRecruiterSvg.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import type { ReactElement } from 'react'; -import React from 'react'; - -export type LogoRecruiterProps = { - className?: { - container?: string; - }; -}; - -export const LogoRecruiterSvg = ({ - className, -}: LogoRecruiterProps): ReactElement => { - return ( - - - - - - - - - - - - - - - - - - - - - - ); -};