update ui design for all pages
This commit is contained in:
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu';
|
||||
import { MessageSquare, Phone, Calendar, X, Trash2, ChevronDown, UserCheck, Briefcase, ExternalLink } from 'lucide-react';
|
||||
import { MessageSquare, Phone, Calendar, X, Trash2, ChevronDown, UserCheck, Briefcase } from 'lucide-react';
|
||||
import { Image } from '@/components/ui/image';
|
||||
import { getScoreBand } from '@/lib/talentHome';
|
||||
import CandidateExpandedDetails from '@/components/krow/CandidateExpandedDetails';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Lock, ShieldCheck, Zap, Clock, ArrowRight, Target } from 'lucide-react';
|
||||
import { Lock, ShieldCheck, Zap, Clock, ArrowRight } from 'lucide-react';
|
||||
import { isUnlocked } from '@/lib/provingGround';
|
||||
|
||||
const DIFF_STYLES = {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import React from 'react';
|
||||
import { Shield, Star, TrendingUp } from 'lucide-react';
|
||||
import { Gauge, gaugeClasses } from '@mui/x-charts/Gauge';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { getScoreBand } from '@/lib/talentHome';
|
||||
import ReferencesEndorsements from '@/components/krow/ReferencesEndorsements';
|
||||
|
||||
const R = 44;
|
||||
const STROKE = 8;
|
||||
const CIRC = 2 * Math.PI * R;
|
||||
const FICO_MIN = 300;
|
||||
const FICO_MAX = 850;
|
||||
|
||||
@@ -29,51 +28,108 @@ function nextTierFromApp(app) {
|
||||
return 'Beginner';
|
||||
}
|
||||
|
||||
function CareerScoreMini({ application }) {
|
||||
/**
|
||||
* The score, its band, and what both are worth — one block, read top to bottom.
|
||||
*
|
||||
* The gauge is the anchor rather than an ornament beside the numbers, so it is
|
||||
* sized to be the first thing seen and carries the score inside it: label, value
|
||||
* and range stacked in the arc's own empty middle, which is the only place where
|
||||
* "834" and "300–850" read as one statement instead of two.
|
||||
*
|
||||
* Everything to the right is interpretation — where this person sits and where
|
||||
* they go next — kept at a subordinate weight so the eye lands on the score
|
||||
* first and travels outward.
|
||||
*/
|
||||
const GAUGE_W = 184;
|
||||
|
||||
function CareerScorePrimary({ application }) {
|
||||
const score = careerScoreFromApp(application);
|
||||
const pct = Math.max(0, Math.min(1, (score - FICO_MIN) / (FICO_MAX - FICO_MIN)));
|
||||
const dash = pct * CIRC;
|
||||
const band = getScoreBand(Math.round(application?.ai_score || 0));
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-5 bg-white/70 rounded-xl border border-[#E5E7EB] px-4 py-3">
|
||||
<div className="flex flex-col items-center shrink-0">
|
||||
<div className="relative" style={{ width: R * 2 + STROKE, height: R * 2 + STROKE }}>
|
||||
<svg width={R * 2 + STROKE} height={R * 2 + STROKE} className="-rotate-90">
|
||||
<circle cx={R + STROKE / 2} cy={R + STROKE / 2} r={R} fill="none" stroke="#EFF6FF" strokeWidth={STROKE} />
|
||||
<circle
|
||||
cx={R + STROKE / 2}
|
||||
cy={R + STROKE / 2}
|
||||
r={R}
|
||||
fill="none"
|
||||
stroke="#0A39DF"
|
||||
strokeWidth={STROKE}
|
||||
strokeLinecap="round"
|
||||
strokeDasharray={`${dash} ${CIRC}`}
|
||||
/>
|
||||
</svg>
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
||||
<span className="text-[8px] uppercase tracking-wide text-[#94A3B8] font-medium">Career Score</span>
|
||||
<span className="text-[22px] font-bold text-[#0A39DF] leading-none">{score}</span>
|
||||
<span className="text-[8px] text-[#94A3B8] font-medium">300-850</span>
|
||||
<div className="grid gap-x-7 gap-y-5 sm:grid-cols-[auto_minmax(0,1fr)] sm:items-center">
|
||||
{/* Layer 1 — the primary signal */}
|
||||
<div className="flex flex-col items-center gap-2.5">
|
||||
<div
|
||||
className="relative shrink-0"
|
||||
style={{ width: GAUGE_W, height: Math.round(GAUGE_W * 0.577) }}
|
||||
>
|
||||
<Gauge
|
||||
value={score}
|
||||
valueMin={FICO_MIN}
|
||||
valueMax={FICO_MAX}
|
||||
startAngle={-90}
|
||||
endAngle={90}
|
||||
innerRadius="89%"
|
||||
outerRadius="100%"
|
||||
cornerRadius="50%"
|
||||
text={() => null}
|
||||
skipAnimation
|
||||
aria-hidden="true"
|
||||
sx={{
|
||||
width: GAUGE_W,
|
||||
height: GAUGE_W,
|
||||
marginTop: `-${Math.round(GAUGE_W * 0.215)}px`,
|
||||
/* Brand blue for the score it earned, a hairline-weight neutral
|
||||
for the rest of the range — the same pairing the rest of the
|
||||
product uses for "achieved against available". */
|
||||
[`& .${gaugeClasses.valueArc}`]: { fill: '#0A39DF' },
|
||||
[`& .${gaugeClasses.referenceArc}`]: { fill: 'hsl(var(--border))' },
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* The arc's middle is empty by construction; the score belongs in it.
|
||||
Stacked with room between each line so the label never crowds the
|
||||
number it is labelling. */}
|
||||
<div
|
||||
className="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center justify-end pb-1"
|
||||
role="img"
|
||||
aria-label={`Career score ${score} of a ${FICO_MIN} to ${FICO_MAX} range. Level: ${band.label}.`}
|
||||
>
|
||||
<span className="text-[9px] font-semibold uppercase leading-none tracking-[0.08em] text-ink-4">
|
||||
Career score
|
||||
</span>
|
||||
<span className="mt-1.5 font-heading text-[32px] font-bold leading-none tabular-nums text-krow-blue">
|
||||
{score}
|
||||
</span>
|
||||
<span className="mt-1.5 text-[10px] font-medium leading-none tabular-nums text-ink-4">
|
||||
{FICO_MIN}–{FICO_MAX}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
className="mt-2 inline-flex items-center justify-center text-[11px] font-bold text-white px-3 py-1 rounded-full w-full"
|
||||
style={{ backgroundColor: band.color }}
|
||||
>
|
||||
|
||||
{/* Layer 2 — the band this score falls in. A status marker, sized like
|
||||
one: the colour is the band's own, carried by a dot rather than by a
|
||||
filled pill the width of the column. */}
|
||||
<Badge variant="outline" size="lg" className="gap-1.5">
|
||||
<span
|
||||
className="h-1.5 w-1.5 rounded-full"
|
||||
style={{ backgroundColor: band.color }}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{band.label}
|
||||
</span>
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex-1 space-y-3">
|
||||
|
||||
{/* Layer 2 — what the score is worth, and what comes next. */}
|
||||
<dl className="grid gap-x-6 gap-y-4 min-[420px]:grid-cols-2 sm:grid-cols-1 lg:grid-cols-2">
|
||||
<div>
|
||||
<p className="text-[10px] uppercase tracking-wide text-[#9CA3AF] font-medium">Potential Market Value</p>
|
||||
<p className="text-[16px] font-bold text-[#111827]">{marketRangeFromApp(application)}</p>
|
||||
<dt className="text-[10px] font-semibold uppercase tracking-[0.06em] text-ink-4">
|
||||
Potential market value
|
||||
</dt>
|
||||
<dd className="mt-1 font-heading text-body-lg font-bold text-ink-1">
|
||||
{marketRangeFromApp(application)}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[10px] uppercase tracking-wide text-[#9CA3AF] font-medium">Next Promotion</p>
|
||||
<p className="text-[14px] font-semibold text-[#0F172A]">{nextTierFromApp(application)}</p>
|
||||
<dt className="text-[10px] font-semibold uppercase tracking-[0.06em] text-ink-4">
|
||||
Next promotion
|
||||
</dt>
|
||||
<dd className="mt-1 font-heading text-body font-semibold text-ink-1">
|
||||
{nextTierFromApp(application)}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -108,15 +164,26 @@ const initialsFor = (name) => {
|
||||
return (parts[0][0] + parts[1][0]).toUpperCase();
|
||||
};
|
||||
|
||||
function StatTile({ label, value, suffix, accent }) {
|
||||
const text = value != null && value !== '' ? value : '—';
|
||||
/**
|
||||
* A supporting signal — evidence for the score, not a headline of its own.
|
||||
*
|
||||
* Label and value on one line, no border, no tile: five bordered boxes under the
|
||||
* gauge read as five more metrics competing with it, which is exactly the
|
||||
* hierarchy this card is meant to establish. Values share one ink colour so no
|
||||
* single signal shouts louder than the rest.
|
||||
*/
|
||||
function SupportingSignal({ label, value, suffix, icon: Icon }) {
|
||||
const shown = value != null && value !== '' ? value : '—';
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center gap-1 px-2 py-3 rounded-xl bg-white/70 border border-[#E5E7EB]">
|
||||
<div className="text-[18px] font-bold leading-none" style={{ color: accent }}>
|
||||
{text}
|
||||
{suffix && <span className="text-[12px] font-semibold ml-0.5">{suffix}</span>}
|
||||
</div>
|
||||
<div className="text-[10px] text-[#6B7280] tracking-wide font-medium">{label}</div>
|
||||
<div className="flex items-baseline justify-between gap-3">
|
||||
<dt className="truncate text-caption text-ink-3">{label}</dt>
|
||||
<dd className="flex shrink-0 items-center font-heading text-body-sm font-bold tabular-nums text-ink-1">
|
||||
{Icon && <Icon className="mr-1 h-3 w-3 text-krow-yellow" fill="currentColor" aria-hidden="true" />}
|
||||
<span>
|
||||
{shown}
|
||||
{suffix && shown !== '—' && <span className="text-caption font-semibold">{suffix}</span>}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -137,37 +204,35 @@ export default function WorkforceReputation({ application }) {
|
||||
if (!hasData) return null;
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-[#E5E7EB] bg-[#F8FAFC] p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<div className="w-7 h-7 rounded-lg bg-[#0A39DF] flex items-center justify-center">
|
||||
<Shield className="w-4 h-4 text-white" strokeWidth={2.5} />
|
||||
<div className="rounded-2xl border border-border bg-surface px-4 py-4">
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<div className="flex h-7 w-7 items-center justify-center rounded-lg bg-krow-blue">
|
||||
<Shield className="h-4 w-4 text-white" strokeWidth={2.5} />
|
||||
</div>
|
||||
<h4 className="text-[12px] font-bold text-[#111827] tracking-wide flex items-center gap-1.5">
|
||||
<h4 className="flex items-center gap-1.5 text-[12px] font-bold tracking-wide text-ink-1">
|
||||
WORKFORCE REPUTATION
|
||||
<TrendingUp className="w-3.5 h-3.5 text-[#0A39DF]" />
|
||||
<TrendingUp className="h-3.5 w-3.5 text-krow-blue" />
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<CareerScoreMini application={application} />
|
||||
<CareerScorePrimary application={application} />
|
||||
|
||||
<div className="grid grid-cols-2 sm:grid-cols-5 gap-2">
|
||||
<StatTile label="Reliability" value={reliability != null ? reliability : null} suffix="%" accent="#0A39DF" />
|
||||
<StatTile label="Attendance" value={attendance != null ? attendance : null} suffix="%" accent="#059669" />
|
||||
<StatTile label="Leadership" value={leadership != null ? leadership : null} suffix="%" accent="#0A39DF" />
|
||||
<StatTile label="Communication" value={commText} accent="#F59E0B" />
|
||||
<div className="flex flex-col items-center justify-center gap-1 px-2 py-3 rounded-xl bg-white/70 border border-[#E5E7EB]">
|
||||
<div className="flex items-center gap-0.5">
|
||||
<Star className="w-3.5 h-3.5 text-[#F9E547] fill-[#F9E547]" />
|
||||
<span className="text-[18px] font-bold leading-none text-[#111827]">
|
||||
{clientRating > 0 ? clientRating.toFixed(1) : '—'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[10px] text-[#6B7280] tracking-wide font-medium">Client Rating</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Layer 3 — supporting evidence. A hairline is enough to separate it from
|
||||
the score; another container would make it a second card. */}
|
||||
<dl className="mt-4 grid grid-cols-1 gap-x-8 gap-y-2 border-t border-border pt-3 min-[420px]:grid-cols-2 lg:grid-cols-3">
|
||||
<SupportingSignal label="Reliability" value={reliability} suffix="%" />
|
||||
<SupportingSignal label="Attendance" value={attendance} suffix="%" />
|
||||
<SupportingSignal label="Leadership" value={leadership} suffix="%" />
|
||||
<SupportingSignal label="Communication" value={commText} />
|
||||
<SupportingSignal
|
||||
label="Client rating"
|
||||
value={clientRating > 0 ? clientRating.toFixed(1) : null}
|
||||
icon={Star}
|
||||
/>
|
||||
</dl>
|
||||
|
||||
{companies.length > 0 && (
|
||||
<div className="mt-3 pt-3 border-t border-[#E5E7EB]/80">
|
||||
<div className="mt-3 border-t border-border pt-3">
|
||||
<p className="text-[10px] font-bold text-[#9CA3AF] tracking-wider mb-2">WORKED</p>
|
||||
<div className="flex flex-wrap items-center gap-2.5">
|
||||
{companies.map((c, i) => (
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
import React from 'react';
|
||||
import { Info, RefreshCw } from 'lucide-react';
|
||||
import { Gauge, gaugeClasses } from '@mui/x-charts/Gauge';
|
||||
import { getTalentScore, toFICO, getScoreBand } from '@/lib/talentHome';
|
||||
|
||||
const FICO_MIN = 300;
|
||||
const FICO_MAX = 850;
|
||||
const ARC_R = 64;
|
||||
const CX = 80;
|
||||
const CY = 80;
|
||||
const BLUE = '#0055FF';
|
||||
const TRACK = '#E1E5E9';
|
||||
|
||||
function arcPoint(p) {
|
||||
const ang = Math.PI - p * Math.PI;
|
||||
return { x: CX + ARC_R * Math.cos(ang), y: CY - ARC_R * Math.sin(ang) };
|
||||
}
|
||||
function arcPath(startP, endP) {
|
||||
const a = arcPoint(startP);
|
||||
const b = arcPoint(endP);
|
||||
const large = endP - startP > 0.5 ? 1 : 0;
|
||||
return `M ${a.x} ${a.y} A ${ARC_R} ${ARC_R} 0 ${large} 1 ${b.x} ${b.y}`;
|
||||
}
|
||||
const BLUE = '#0A39DF';
|
||||
|
||||
export default function CareerScoreGauge({ profile }) {
|
||||
const raw = getTalentScore(profile);
|
||||
const score = toFICO(raw);
|
||||
const band = getScoreBand(raw);
|
||||
const pct = Math.max(0, Math.min(1, (score - FICO_MIN) / (FICO_MAX - FICO_MIN)));
|
||||
const gap = 0.02;
|
||||
const filledEnd = Math.max(gap, Math.min(1 - gap, pct));
|
||||
const marker = arcPoint(filledEnd);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="relative" style={{ width: CX * 2, height: CY + 28 }}>
|
||||
<svg width={CX * 2} height={CY + 28} viewBox={`0 0 ${CX * 2} ${CY + 28}`} className="overflow-visible">
|
||||
<path d={arcPath(gap, 1 - gap)} fill="none" stroke={TRACK} strokeWidth="12" strokeLinecap="round" />
|
||||
{pct > gap && (
|
||||
<path d={arcPath(gap, filledEnd)} fill="none" stroke={BLUE} strokeWidth="12" strokeLinecap="round" />
|
||||
)}
|
||||
<circle cx={marker.x} cy={marker.y} r="8" fill={BLUE} stroke="#fff" strokeWidth="3" />
|
||||
</svg>
|
||||
<div className="relative flex items-center justify-center" style={{ width: 140, height: 80 }}>
|
||||
<Gauge
|
||||
value={score}
|
||||
valueMin={FICO_MIN}
|
||||
valueMax={FICO_MAX}
|
||||
startAngle={-90}
|
||||
endAngle={90}
|
||||
innerRadius="75%"
|
||||
outerRadius="100%"
|
||||
cornerRadius="50%"
|
||||
text={() => null}
|
||||
sx={{
|
||||
width: 140,
|
||||
height: 140,
|
||||
marginTop: '-30px',
|
||||
[`& .${gaugeClasses.valueArc}`]: {
|
||||
fill: BLUE,
|
||||
},
|
||||
[`& .${gaugeClasses.referenceArc}`]: {
|
||||
fill: '#E2E8F0',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="absolute inset-x-0 bottom-2 flex flex-col items-center">
|
||||
<span className="text-[9px] uppercase tracking-wide text-[#A0AAB9] font-semibold">Career Score</span>
|
||||
<span className="text-[30px] font-bold leading-none mt-0.5" style={{ color: BLUE }}>{score}</span>
|
||||
<span className="text-[10px] text-[#8690A1] font-medium mt-0.5">{FICO_MIN}-{FICO_MAX}</span>
|
||||
<div
|
||||
className="absolute inset-x-0 bottom-0 flex flex-col items-center justify-end pb-1 pointer-events-none"
|
||||
aria-label={`Career Score: ${score}, Range: ${FICO_MIN}-${FICO_MAX}`}
|
||||
>
|
||||
<span className="text-[9px] uppercase tracking-wider text-[#94A3B8] font-semibold">CAREER SCORE</span>
|
||||
<span className="text-[24px] font-extrabold text-[#0A39DF] leading-none mt-0.5 tabular-nums">{score}</span>
|
||||
<span className="text-[9px] text-[#8690A1] font-medium mt-0.5">{FICO_MIN}–{FICO_MAX}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useRef, useState } from 'react';
|
||||
import html2canvas from 'html2canvas';
|
||||
import { Wallet, Smartphone, Image as ImageIcon, ShieldCheck, Briefcase, Sparkles, QrCode, Download, Check, Info, RefreshCw } from 'lucide-react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Gauge as MuiGauge, gaugeClasses } from '@mui/x-charts/Gauge';
|
||||
import { Image } from '@/components/ui/image';
|
||||
import { getTalentScore, getScoreBand, getGrowth } from '@/lib/talentHome';
|
||||
|
||||
@@ -47,39 +48,40 @@ function download(filename, content, type) {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
const BLUE = '#0055FF';
|
||||
const TRACK = '#E1E5E9';
|
||||
const ARC_R = 64;
|
||||
const CX = 80;
|
||||
const CY = 80;
|
||||
function arcPoint(p) {
|
||||
const ang = Math.PI - p * Math.PI;
|
||||
return { x: CX + ARC_R * Math.cos(ang), y: CY - ARC_R * Math.sin(ang) };
|
||||
}
|
||||
function arcPath(startP, endP) {
|
||||
const a = arcPoint(startP);
|
||||
const b = arcPoint(endP);
|
||||
const large = endP - startP > 0.5 ? 1 : 0;
|
||||
return `M ${a.x} ${a.y} A ${ARC_R} ${ARC_R} 0 ${large} 1 ${b.x} ${b.y}`;
|
||||
}
|
||||
const BLUE = '#0A39DF';
|
||||
|
||||
function Gauge({ fico }) {
|
||||
const pct = Math.max(0, Math.min(1, (fico - 300) / 550));
|
||||
const gap = 0.02;
|
||||
const filledEnd = Math.max(gap, Math.min(1 - gap, pct));
|
||||
const marker = arcPoint(filledEnd);
|
||||
return (
|
||||
<div className="relative mx-auto" style={{ width: CX * 2, height: CY + 18 }}>
|
||||
<svg width={CX * 2} height={CY + 18} viewBox={`0 0 ${CX * 2} ${CY + 18}`}>
|
||||
<path d={arcPath(gap, 1 - gap)} fill="none" stroke={TRACK} strokeWidth="12" strokeLinecap="round" />
|
||||
{pct > gap && (
|
||||
<path d={arcPath(gap, filledEnd)} fill="none" stroke={BLUE} strokeWidth="12" strokeLinecap="round" />
|
||||
)}
|
||||
<circle cx={marker.x} cy={marker.y} r="8" fill={BLUE} stroke="#fff" strokeWidth="3" />
|
||||
</svg>
|
||||
<div className="absolute inset-x-0 bottom-1 flex flex-col items-center">
|
||||
<span className="text-[9px] uppercase tracking-wide text-[#A0AAB9] font-semibold">Career Score</span>
|
||||
<span className="text-[28px] font-bold leading-none mt-0.5" style={{ color: BLUE }}>{fico}</span>
|
||||
<span className="text-[10px] text-[#8690A1] font-medium mt-0.5">300-850</span>
|
||||
<div className="relative mx-auto flex items-center justify-center" style={{ width: 140, height: 80 }}>
|
||||
<MuiGauge
|
||||
value={fico}
|
||||
valueMin={300}
|
||||
valueMax={850}
|
||||
startAngle={-90}
|
||||
endAngle={90}
|
||||
innerRadius="75%"
|
||||
outerRadius="100%"
|
||||
cornerRadius="50%"
|
||||
text={() => null}
|
||||
sx={{
|
||||
width: 140,
|
||||
height: 140,
|
||||
marginTop: '-30px',
|
||||
[`& .${gaugeClasses.valueArc}`]: {
|
||||
fill: BLUE,
|
||||
},
|
||||
[`& .${gaugeClasses.referenceArc}`]: {
|
||||
fill: '#E2E8F0',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-x-0 bottom-0 flex flex-col items-center justify-end pb-1 pointer-events-none"
|
||||
aria-label={`Career Score: ${fico}, Range: 300-850`}
|
||||
>
|
||||
<span className="text-[9px] uppercase tracking-wider text-[#94A3B8] font-semibold">CAREER SCORE</span>
|
||||
<span className="text-[24px] font-extrabold text-[#0A39DF] leading-none mt-0.5 tabular-nums">{fico}</span>
|
||||
<span className="text-[9px] text-[#8690A1] font-medium mt-0.5">300–850</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user