Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions src/components/ProviderCard/ProviderCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ const ProviderLogo: React.FC<{

if (!logoURL || hasError) {
return (
<div className={cn(logoContainerVariants({ variant }))}>
<div
data-slot="provider-card-logo"
className={cn(logoContainerVariants({ variant }))}
>
<div className="bg-primary-100 dark:bg-primary-900 flex h-12 w-12 items-center justify-center rounded-full">
<span className="text-primary-800 dark:text-primary-300 text-lg font-bold">
{name.charAt(0).toUpperCase()}
Expand All @@ -107,7 +110,10 @@ const ProviderLogo: React.FC<{
}

return (
<div className={cn(logoContainerVariants({ variant }))}>
<div
data-slot="provider-card-logo"
className={cn(logoContainerVariants({ variant }))}
>
<img
src={logoURL}
alt={`${name}'s logo`}
Expand Down Expand Up @@ -149,7 +155,10 @@ const DistanceBadge: React.FC<{ distance?: number }> = ({ distance }) => {

const SafeFromWildfiresNotice: React.FC = () => (
<Tooltip content="BlueHive has confirmed that this provider is operational and not impacted by the January 2025 wildfires.">
<div className="inline-flex items-center gap-1.5 rounded-md bg-green-100 px-2 py-1 text-xs text-green-700 dark:bg-green-900/30 dark:text-green-300">
<div
data-slot="provider-card-safe-notice"
className="inline-flex items-center gap-1.5 rounded-md bg-green-100 px-2 py-1 text-xs text-green-700 dark:bg-green-900/30 dark:text-green-300"
>
<svg className="h-4 w-4" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
Expand All @@ -164,7 +173,10 @@ const SafeFromWildfiresNotice: React.FC = () => (

const VerifiedBadge: React.FC = () => (
<Tooltip content="This provider's information has been verified">
<span className="inline-flex items-center gap-1 text-xs text-green-700 dark:text-green-300">
<span
data-slot="provider-card-verified"
className="inline-flex items-center gap-1 text-xs text-green-700 dark:text-green-300"
>
<svg className="h-3.5 w-3.5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
Expand Down Expand Up @@ -298,6 +310,8 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(
tabIndex={interactive ? 0 : undefined}
role={interactive ? 'button' : undefined}
aria-label={`View ${provider.name}`}
data-slot="provider-card"
data-variant={variant}
data-testid="provider-card"
{...props}
>
Expand All @@ -319,6 +333,7 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(

{/* Content Section */}
<div
data-slot="provider-card-content"
className={cn(
'flex flex-1 flex-col',
variant === 'compact' && 'p-4',
Expand All @@ -327,7 +342,10 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(
)}
>
{/* Header: Name + Verified */}
<div className="mb-1 flex items-start justify-between gap-2">
<div
data-slot="provider-card-header"
className="mb-1 flex items-start justify-between gap-2"
>
<h3
className={cn(
'text-primary-800 dark:text-primary-300 line-clamp-2 font-semibold',
Expand All @@ -343,6 +361,7 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(

{/* Address */}
<p
data-slot="provider-card-address"
className={cn(
'text-muted-foreground',
variant === 'featured' ? 'text-sm' : 'text-xs'
Expand Down Expand Up @@ -370,6 +389,7 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(
{provider.workNumber && (
<a
href={`tel:${provider.workNumber}`}
data-slot="provider-card-phone"
data-phone-link
onClick={handlePhoneClick}
className={cn(
Expand All @@ -385,7 +405,10 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(

{/* Services Badges */}
{displayServices && displayServices.length > 0 && (
<div className="mt-3 flex flex-wrap gap-1.5">
<div
data-slot="provider-card-services"
className="mt-3 flex flex-wrap gap-1.5"
>
{displayServices.map((service) => (
<Badge
key={service._id}
Expand All @@ -408,7 +431,10 @@ export const ProviderCard = React.forwardRef<HTMLDivElement, ProviderCardProps>(
<div className="flex-1" />

{/* Footer: Distance + Actions */}
<div className="mt-3 flex items-center justify-between">
<div
data-slot="provider-card-footer"
className="mt-3 flex items-center justify-between"
>
<div className="flex items-center gap-2">
{provider.safeFromWildfires && <SafeFromWildfiresNotice />}
{!provider.safeFromWildfires && (
Expand Down Expand Up @@ -468,6 +494,7 @@ export const ProviderCardGrid: React.FC<ProviderCardGridProps> = ({
if (loading) {
return (
<div
data-slot="provider-card-grid"
className={cn(
'grid gap-4',
variant === 'compact' && 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
Expand All @@ -484,7 +511,10 @@ export const ProviderCardGrid: React.FC<ProviderCardGridProps> = ({

if (providers.length === 0) {
return (
<div className={cn('py-12 text-center', className)}>
<div
data-slot="provider-card-grid"
className={cn('py-12 text-center', className)}
>
{emptyState || (
<div className="text-muted-foreground">
<svg
Expand Down Expand Up @@ -512,6 +542,7 @@ export const ProviderCardGrid: React.FC<ProviderCardGridProps> = ({

return (
<div
data-slot="provider-card-grid"
className={cn(
'grid gap-4',
variant === 'compact' && 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
Expand Down
181 changes: 181 additions & 0 deletions src/styles/condensed-view.css
Original file line number Diff line number Diff line change
Expand Up @@ -9841,3 +9841,184 @@ body.condensed [data-slot='pending-claims-card'] button {
height: auto !important;
min-height: 0 !important;
}

/* ═══════════════════════════════════════════════════════════════
ProviderCard – condensed overrides
═══════════════════════════════════════════════════════════════ */

/* ── Card root ── */

body.condensed [data-slot='provider-card'] {
border-radius: 0.5rem !important;
}

body.condensed [data-slot='provider-card'][data-variant='list'] {
min-height: 5rem !important;
}

body.condensed [data-slot='provider-card'][data-variant='featured'] {
padding: 0 !important;
}

/* ── Logo (compact / featured) ── */

body.condensed
[data-slot='provider-card'][data-variant='compact']
[data-slot='provider-card-logo'] {
height: 3rem !important;
}

body.condensed
[data-slot='provider-card'][data-variant='featured']
[data-slot='provider-card-logo'] {
height: 3rem !important;
margin-bottom: 0.25rem !important;
border-radius: 0 !important;
}

/* ── Logo (list) ── */

body.condensed
[data-slot='provider-card'][data-variant='list']
[data-slot='provider-card-logo'] {
width: 5rem !important;
}

/* ── Logo inner (fallback initial circle + image) ── */

body.condensed [data-slot='provider-card-logo'] > div {
width: 1.75rem !important;
height: 1.75rem !important;
}

body.condensed [data-slot='provider-card-logo'] > div span {
font-size: 0.75rem !important;
}

body.condensed [data-slot='provider-card-logo'] img {
padding: 0.25rem !important;
}

/* ── Content ── */

body.condensed [data-slot='provider-card-content'] {
padding: 0.375rem 0.5rem !important;
}

body.condensed
[data-slot='provider-card'][data-variant='featured']
[data-slot='provider-card-content'] {
padding: 0.375rem 0.5rem !important;
}

/* ── Header (name + verified) ── */

body.condensed [data-slot='provider-card-header'] {
margin-bottom: 0.125rem !important;
gap: 0.25rem !important;
}

body.condensed [data-slot='provider-card-header'] h3 {
font-size: 0.75rem !important;
line-height: 1rem !important;
}

body.condensed
[data-slot='provider-card'][data-variant='featured']
[data-slot='provider-card-header']
h3 {
font-size: 0.75rem !important;
line-height: 1rem !important;
}

body.condensed [data-slot='provider-card-verified'] {
font-size: 0.5625rem !important;
}

body.condensed [data-slot='provider-card-verified'] svg {
width: 0.625rem !important;
height: 0.625rem !important;
}

/* ── Address ── */

body.condensed [data-slot='provider-card-address'] {
font-size: 0.625rem !important;
line-height: 0.875rem !important;
}

body.condensed
[data-slot='provider-card'][data-variant='featured']
[data-slot='provider-card-address'] {
font-size: 0.625rem !important;
line-height: 0.875rem !important;
}

/* ── Phone ── */

body.condensed [data-slot='provider-card-phone'] {
font-size: 0.625rem !important;
margin-top: 0.125rem !important;
}

/* ── Services badges ── */

body.condensed [data-slot='provider-card-services'] {
margin-top: 0.25rem !important;
gap: 0.25rem !important;
}

body.condensed [data-slot='provider-card-services'] [data-slot='badge'] {
font-size: 0.5625rem !important;
padding: 0 0.25rem !important;
}

/* ── Footer (distance + actions) ── */

body.condensed [data-slot='provider-card-footer'] {
margin-top: 0.25rem !important;
}

body.condensed [data-slot='provider-card-footer'] span {
font-size: 0.5625rem !important;
}

body.condensed [data-slot='provider-card-footer'] span svg {
width: 0.5rem !important;
height: 0.5rem !important;
}

/* ── Safe from wildfires notice ── */

body.condensed [data-slot='provider-card-safe-notice'] {
font-size: 0.5625rem !important;
padding: 0.0625rem 0.25rem !important;
gap: 0.25rem !important;
}

body.condensed [data-slot='provider-card-safe-notice'] svg {
width: 0.625rem !important;
height: 0.625rem !important;
}

/* ── Grid ── */

body.condensed [data-slot='provider-card-grid'] {
gap: 0.5rem !important;
}

/* ── Grid empty state ── */

body.condensed [data-slot='provider-card-grid'] > div > svg {
width: 1.5rem !important;
height: 1.5rem !important;
margin-bottom: 0.375rem !important;
}

body.condensed [data-slot='provider-card-grid'] > div > p:first-of-type {
font-size: 0.875rem !important;
}

body.condensed [data-slot='provider-card-grid'] > div > p + p {
font-size: 0.75rem !important;
}
Loading