Update Konten & bahasa
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-09-28 16:48:14 +07:00
parent 566275348c
commit 183f36f634
29 changed files with 3285 additions and 1427 deletions
+227 -472
View File
@@ -1,246 +1,46 @@
import { Head } from '@inertiajs/react';
import { useState } from 'react';
import { ButtonLink } from '@/components/site/button';
import { Button, ButtonLink } from '@/components/site/button';
import Card from '@/components/site/card';
import Eyebrow from '@/components/site/eyebrow';
import FeatureCard from '@/components/site/feature-card';
import Glow from '@/components/site/glow';
import Icon from '@/components/site/icon';
import IconTile from '@/components/site/icon-tile';
import ImageCard from '@/components/site/image-card';
import PageHero, { Highlight } from '@/components/site/page-hero';
import PageHero from '@/components/site/page-hero';
import RichText from '@/components/site/rich-text';
import Section from '@/components/site/section';
import SectionHeader from '@/components/site/section-header';
import CtaBanner from '@/components/site/sections/cta-banner';
import { clientsContent } from '@/content/clients';
import type { ProjectSector } from '@/data/projects';
import {
projectsBySector,
projectsInProgram,
yearRange,
} from '@/data/projects';
import { company, consultationUrl, officeAddress, offices } from '@/data/site';
import { useContent } from '@/hooks/use-locale';
import { cn } from '@/lib/utils';
import { contact } from '@/routes';
type Sector = 'energy' | 'steel' | 'corporate';
const filters: { value: Sector | 'all'; label: string }[] = [
{ value: 'all', label: 'Semua Sektor (5)' },
{ value: 'energy', label: 'Migas & Energi' },
{ value: 'steel', label: 'Baja & Manufaktur' },
{ value: 'corporate', label: 'Holding & BUMN' },
];
const heroStats = [
{ value: '100+', caption: 'Proyek Enterprise & BUMN' },
{ value: '40+ Thn', caption: 'Integritas Reputasi (Est. 1985)' },
{ value: '99.8%', caption: 'Tingkat Retensi & Kepuasan' },
{ value: '0%', caption: 'Vendor Lock-in Terbuka' },
];
type IndustrySector = {
sector: Sector;
icon: string;
code: string;
tag: string;
title: string;
description: string;
details: { label: string; text: string }[];
footnote: string;
wide?: boolean;
};
const industrySectors: IndustrySector[] = [
{
sector: 'energy',
icon: 'local_fire_department',
code: 'SEKTOR 01 // MIGAS & ENERGI',
tag: 'Hulu - Hilir & Offshore',
title: 'Minyak, Gas & Energi (Oil & Gas Infrastructure)',
description:
'Arsitektur penanganan aset berisiko tinggi dengan validasi berlapis untuk menjaga kontinuitas suplai serta kepatuhan ketat audit operasional SKK Migas.',
details: [
{
label: 'Karakteristik Kebutuhan Sistem',
text: 'Inventory tracing material kritis, kepatuhan keselamatan kilang kerja, otomatisasi pengadaan & logistik kapal lepas pantai, serta sinkronisasi telemetri multi-site.',
},
{
label: 'Solusi yang Diimplementasikan',
text: 'Tailor-fit ERP supply chain, specialized barcode asset tracking, customized multi-tiered approval pipeline dengan verifikasi digital.',
},
],
footnote: 'Kepatuhan Operasi: ISO 9001 / SKK Migas',
wide: true,
},
{
sector: 'steel',
icon: 'precision_manufacturing',
code: 'SEKTOR 02 // METALURGI',
tag: 'Heavy Steel',
title: 'Fabrikasi & Pengolahan Baja',
description:
'Otomasi perhitungan yield peleburan presisi tinggi dan integrasi rantai produksi dari bahan mentah hingga sertifikat mutu akhir.',
details: [
{
label: 'Fitur Utama Arsitektur',
text: 'Modul spesifik BOM multi-level, manajemen heat-treatment baja, pencatatan scrap & yield otomatis, serta verifikasi sertifikat material uji (Mill Test Cert).',
},
{
label: 'Paket Solusi PAJ',
text: 'SCADA to ERP bridge engine, custom manufacturing execution modules & Quality Assurance Tracker.',
},
],
footnote: 'Presisi BOM: 99.9% Akurasi',
},
{
sector: 'steel',
icon: 'local_shipping',
code: 'SEKTOR 03 // LOGISTIK',
tag: 'Supply Chain',
title: 'Manufaktur & Logistik Terpadu',
description:
'Sinkronisasi rantai pasok multi-gudang secara real-time dengan algoritma penilaian persediaan akurat.',
details: [
{
label: 'Spesifikasi Sistem',
text: 'Multi-warehouse inventory, otomatisasi replenishment dinamis, cross-docking tracking, barcode/RFID scanner terintegrasi, dan valuasi FIFO/Average otomatis.',
},
{
label: 'Solusi PAJ',
text: 'Odoo Custom Supply Chain Suite, live dispatch scheduling, dan mobile warehouse barcode system.',
},
],
footnote: 'Latency Tracking: < 0.8 Detik',
},
{
sector: 'corporate',
icon: 'account_balance',
code: 'SEKTOR 04 // ENTERPRISE & BUMN',
tag: 'Financial Core',
title: 'Korporasi Swasta, Holding & BUMN Nasional',
description:
'Arsitektur sentralisasi keuangan grup dengan keselarasan regulasi perpajakan Indonesia, dirancang untuk auditabilitas instan dan tata kelola korporat terbuka.',
details: [
{
label: 'Karakteristik & Kepatuhan',
text: 'Konsolidasi neraca multi-company, otomasi e-Faktur Pajak DJP terintegrasi langsung tanpa input berulang, eliminasi resiko denda fiskal, dan audit trail lengkap.',
},
{
label: 'Jenis Solusi PAJ',
text: 'Odoo ERP Enterprise Financials, dedicated DJP e-Faktur API Bridge, multi-currency ledger, dan Executive Boardroom C-Suite Dashboard.',
},
],
footnote: 'Integrasi Resmi: DJP e-Faktur Ready',
wide: true,
},
];
const caseStudies = [
{
icon: 'anchor',
title: 'Otomasi Siklus Supply Chain & Logistik Migas Lepas Pantai',
client: 'Klien Eksplorasi & Pengeboran Lepas Pantai',
challenge:
'Tingginya waktu tunggu suku cadang kritis rig pengeboran akibat proses pengadaan birokratis dan ketidakcocokan inventaris antar kapal suplai.',
solution:
'Implementasi tailor-fit inventory hub dengan offline sync capability di kapal kru dan otomatisasi persetujuan anggaran berjenjang.',
results: [
['Waktu Pengadaan Material', '-65%'],
['Keterlambatan Kapal Kerja', 'Nol Insiden'],
['Kepatuhan Audit SKK', '100% Lolos'],
],
},
{
icon: 'factory',
title: 'Integrasi ERP Manufaktur Fabrikasi Baja & Uji Mutu',
client: 'Produsen Baja Konstruksi & Pipa Berat',
challenge:
'Perhitungan estimasi bahan baku sering meleset akibat kompleksitas pemotongan baja (cutting optimization) dan sertifikat mill test manual.',
solution:
'Engine kustom integrasi SCADA mesin potong plasma dengan modul ERP Bill of Materials dan repository digital sertifikasi mutu.',
results: [
['Akurasi Perhitungan BOM', '99.9% Presisi'],
['Traceability Serial Leburan', 'Instan < 5 Detik'],
['Reduksi Scrap Material', '-18.4%'],
],
},
{
icon: 'account_balance_wallet',
title: 'Transformasi Multi-Company Odoo & Integrasi e-Faktur DJP',
client: 'Holding Grup Distribusi & Ritel Nasional',
challenge:
'Penerbitan 15.000+ faktur pajak per bulan dilakukan via input ganda terpisah yang memicu keterlambatan pelaporan SPT bulanan hingga 2 pekan.',
solution:
'Implementasi Odoo ERP terpusat dengan direct bridge connector DJP Pajak otomatis, QR Code approval, dan auto-reconciliation perbankan.',
results: [
['Rekonsiliasi Pajak Bulanan', '2 Hari (Dulu 14 Hari)'],
['Kesalahan Entri Faktur', '0% (Zero Error)'],
['Penerbitan Laporan Holding', 'Otomatis H+1'],
],
},
];
const reasons = [
{
icon: 'handshake',
title: 'Hubungan Jangka Panjang (SCSR)',
description:
'Pemeliharaan berkesinambungan dan program Special CSR berkala memastikan sistem Anda senantiasa relevan mengikuti ekspansi kapasitas bisnis.',
},
{
icon: 'lock_open',
title: 'Bebas Keterikatan Vendor',
description:
'Full source code handover & arsitektur modular mandiri. PAJ memberikan kebebasan mutlak bagi klien atas kepemilikan aset perangkat lunaknya.',
},
{
icon: 'gavel',
title: 'Kepatuhan Regulasi Nasional',
description:
'Kepatuhan langsung sistem akuntansi terhadap peraturan Ditjen Pajak (DJP e-Faktur terintegrasi), standar audit PSAK, dan peraturan kementerian terkait.',
},
{
icon: 'support_agent',
title: 'SLA Tanggap Darurat Khusus',
description:
'Dukungan teknis dedicated tingkat lead architect dengan target mitigasi masalah kritis cepat demi menjaga uptime operasional industri non-stop.',
},
];
const testimonials = [
{
initials: 'DO',
quote: 'Keahlian teknis tim PAJ dalam memahami proses rolling baja dan pemetaan sertifikat heat treatment sangat luar biasa. Sistem berjalan stabil tanpa kendala berarti selama lebih dari 6 tahun operasional.',
role: 'Direktur Operasional',
organization: 'Manufaktur Baja & Fabrikasi Logam',
},
{
initials: 'HI',
quote: 'Integrasi Odoo dengan bridging DJP Faktur memangkas beban kerja departemen akuntansi kami secara drastis. Yang paling berharga adalah transparansi arsitekturnya, tidak ada ketergantungan yang menyulitkan.',
role: 'Head of Enterprise IT',
organization: 'Holding Korporasi & Ritel Nasional',
},
{
initials: 'ML',
quote: 'Di industri migas, keandalan sistem material tracing adalah penentu keselamatan kerja rig. PAJ merancang alur verifikasi logistik yang sangat presisi dan mampu bertahan di koneksi satelit minim.',
role: 'Manajer Logistik & Rantai Pasok',
organization: 'Konsorsium Migas Lepas Pantai',
},
];
type Content = typeof clientsContent.id;
export default function Clients() {
const t = useContent(clientsContent);
return (
<>
<Head title="Klien & Portofolio" />
<Head title={t.title} />
<PageHero
align="center"
badge="Kemitraan Strategis & Portofolio Klien // PT Probindo Artika Jaya"
title={
<>
Kepercayaan Industri Terkemuka,{' '}
<Highlight>Rekam Jejak 40+ Tahun</Highlight>{' '}
Transformasi Digital
</>
}
description="“Kami mengucapkan terima kasih atas kepercayaan dan dukungan Anda sebagai klien kami. Sebagai tim konsultan IT di PT Probindo Artika Jaya (PAJ), kami berkomitmen untuk menyediakan solusi teknologi informasi yang berkualitas tinggi, tailor-fit, dan memberikan nilai tambah nyata bagi kesinambungan bisnis Anda.”"
badge={t.hero.badge}
title={<RichText text={t.hero.title} />}
description={t.hero.description}
>
<Card className="grid w-full max-w-5xl grid-cols-2 gap-4 md:grid-cols-4">
{heroStats.map((stat) => (
{t.hero.stats.map((stat) => (
<div
key={stat.caption}
className="bg-surface-container flex flex-col items-center justify-center rounded-lg p-4 text-center"
@@ -260,137 +60,56 @@ export default function Clients() {
<div className="grid grid-cols-1 items-center gap-8 lg:grid-cols-12">
<div className="flex flex-col gap-6 lg:col-span-5">
<Eyebrow icon="verified_user">
Warisan Teknis Sejak 1985
{t.heritage.eyebrow}
</Eyebrow>
<h2 className="font-display text-on-surface lg:text-headline-xl text-3xl leading-tight font-extrabold">
Fondasi Rekayasa Industri Menuju Otomasi Mutakhir
{t.heritage.title}
</h2>
<p className="text-on-surface-variant text-base leading-relaxed">
Berakar kuat dari kiprah awal perseroan pada sektor
perdagangan migas dan baja berat di era 1980-an, PAJ
berevolusi penuh pada 2002 menjadi sentra konsultan
sistem informasi terpadu. Pemahaman mendalam
mengenai dinamika lapangan, kepatuhan fiskal
nasional, serta kompleksitas supply chain menjadikan
solusi PAJ berakar pada kenyataan operasional, bukan
sekadar perangkat lunak generik.
{t.heritage.description}
</p>
<Card padding="sm" className="flex items-start gap-4">
<IconTile icon="hub" tone="solid" />
<div>
<h3 className="font-display text-on-surface text-lg font-semibold">
Special CSR (SCSR) Architecture
{t.heritage.scsrTitle}
</h3>
<p className="text-on-surface-variant mt-1 text-sm">
Sistem pendampingan kapasitas berkelanjutan
memastikan kapabilitas internal klien
meningkat secara mandiri tanpa jebakan
lisensi tertutup.
{t.heritage.scsrText}
</p>
</div>
</Card>
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:col-span-7">
<ImageCard
src="/images/probindo/clients-operations-center.jpg"
alt="Pusat operasi rekayasa dengan monitor telemetri industri"
eyebrow="Heavy Industry Matrix"
title="Migas & Fabrikasi Metalurgi"
/>
<ImageCard
src="/images/probindo/clients-erp-dashboard.jpg"
alt="Dasbor ERP enterprise dengan sinkronisasi pajak DJP"
eyebrow="Enterprise Core"
title="Holding Multinasional & BUMN"
className="sm:translate-y-8"
/>
</div>
</div>
</Section>
<SectorPortfolio />
<Section>
<div className="flex flex-col gap-12">
<SectionHeader
eyebrow="Impact Stories // Rekam Jejak Unggulan"
title="Studi Kasus Efisiensi & Keberhasilan Terukur"
description="Bukti nyata transformasi arsitektur digital teruji di lingkungan operasional bertekanan tinggi dengan metodologi PAJ."
/>
<div className="grid grid-cols-1 gap-8 md:grid-cols-3">
{caseStudies.map((study, index) => (
<Card
key={study.title}
padding="none"
className="flex flex-col overflow-hidden"
>
<div className="bg-surface-container flex flex-col gap-3 p-6">
<div className="flex items-center justify-between">
<span className="text-primary font-mono text-xs font-bold">
STUDI KASUS 0{index + 1}
</span>
<Icon
name={study.icon}
className="text-on-surface-variant text-xl"
/>
</div>
<h3 className="font-display text-on-surface text-lg leading-snug font-bold">
{study.title}
</h3>
<span className="text-highlight text-xs font-semibold">
{study.client}
</span>
</div>
<div className="flex flex-1 flex-col justify-between gap-6 p-6">
<div className="space-y-4">
<DetailBlock
label="Tantangan Klien"
text={study.challenge}
/>
<DetailBlock
label="Solusi Arsitektur PAJ"
text={study.solution}
/>
</div>
<div className="bg-surface-container-high flex flex-col gap-2 rounded-lg p-4">
<span className="text-highlight font-mono text-[11px] font-bold">
DAMPAK TERVERIFIKASI:
</span>
{study.results.map(
([metric, result]) => (
<div
key={metric}
className="flex items-baseline justify-between gap-3"
>
<span className="text-on-surface text-sm">
{metric}
</span>
<span className="text-primary shrink-0 font-mono text-sm font-bold">
{result}
</span>
</div>
),
)}
</div>
</div>
</Card>
{t.heritage.images.map((image, index) => (
<ImageCard
key={image.src}
{...image}
className={
index === 1 ? 'sm:translate-y-8' : ''
}
/>
))}
</div>
</div>
</Section>
<SectorPortfolio t={t} />
<FeaturedPrograms t={t} />
<Section tone="muted">
<div className="flex flex-col gap-12">
<SectionHeader
align="center"
eyebrow="Nilai Inti Kemitraan"
title="Mengapa Mitra Korporasi Memilih PAJ Sejak 1985"
description="Komitmen arsitektur terbuka dan pendampingan tanpa henti menciptakan relasi kemitraan yang melintasi dekade."
eyebrow={t.reasons.eyebrow}
title={t.reasons.title}
description={t.reasons.description}
/>
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
{reasons.map((reason) => (
{t.reasons.items.map((reason) => (
<FeatureCard
key={reason.title}
key={reason.icon}
iconTone="solid"
{...reason}
/>
@@ -403,12 +122,12 @@ export default function Clients() {
<div className="flex flex-col gap-12">
<SectionHeader
align="split"
eyebrow="Suara Mitra Kami"
title="Testimoni & Pernyataan Kepercayaan"
description="Apresiasi nyata atas komitmen tanpa henti dari tim konsultan teknis PT Probindo Artika Jaya."
eyebrow={t.testimonials.eyebrow}
title={t.testimonials.title}
description={t.testimonials.description}
/>
<div className="grid grid-cols-1 gap-6 md:grid-cols-3">
{testimonials.map((testimonial) => (
{t.testimonials.items.map((testimonial) => (
<Card
key={testimonial.initials}
className="flex flex-col justify-between gap-6"
@@ -416,7 +135,7 @@ export default function Clients() {
<div className="space-y-4">
<div
className="text-primary flex"
aria-label="Rating 5 dari 5"
aria-label={t.testimonials.rating}
>
{Array.from({ length: 5 }, (_, i) => (
<Icon key={i} name="star" filled />
@@ -451,22 +170,15 @@ export default function Clients() {
className="flex flex-col items-center justify-between gap-10 lg:flex-row lg:p-12"
>
<div className="max-w-xl">
<Eyebrow>Reliability Index &amp; Audit Trail</Eyebrow>
<Eyebrow>{t.reliability.eyebrow}</Eyebrow>
<h2 className="font-display text-headline-lg text-on-surface mt-3 mb-4 font-bold">
Stabilitas Operasional di Atas Standar Industri
{t.reliability.title}
</h2>
<p className="text-on-surface-variant mb-6 text-base leading-relaxed">
Setiap sistem yang dibangun oleh tim insinyur PAJ
melalui protokol verifikasi beban puncak (stress
test), audit kepatuhan tahunan, serta program
pemeliharaan terstruktur guna memastikan ketiadaan
downtime tidak terencana.
{t.reliability.description}
</p>
<div className="grid grid-cols-2 gap-4">
{[
['99.98%', 'System Availability'],
['< 15 Mnt', 'Mitigasi Respon Krisis'],
].map(([value, label]) => (
{t.reliability.metrics.map(([value, label]) => (
<div
key={label}
className="bg-surface-container rounded-lg p-4"
@@ -481,28 +193,28 @@ export default function Clients() {
))}
</div>
</div>
<RetentionGauge />
<RetentionGauge t={t} />
</Card>
</Section>
<CtaBanner
badge="Konsultasi Teknis & Audit Infrastruktur"
title="Siap Menjadi Mitra Transformasi Digital Berikutnya?"
description="Diskusikan tantangan arsitektur sistem dan otomasi proses bisnis Anda bersama Lead Architect PAJ. Kami siap menghadirkan solusi tailor-fit yang terukur."
badge={t.cta.badge}
title={t.cta.title}
description={t.cta.description}
actions={
<>
<ButtonLink
href={consultationUrl}
icon="event_available"
>
Jadwalkan Diskusi Teknis
{t.cta.primary}
</ButtonLink>
<ButtonLink
href={`${contact.url()}#lokasi`}
variant="secondary"
icon="apartment"
>
Lihat Lokasi Kantor PAJ
{t.cta.secondary}
</ButtonLink>
</>
}
@@ -520,11 +232,10 @@ export default function Clients() {
className="h-12 w-auto self-start object-contain"
/>
<h2 className="font-display text-on-surface text-lg font-bold">
Kantor Operasional &amp; IT Consultant Desk
{t.office.title}
</h2>
<p className="text-on-surface-variant text-sm">
Pusat koordinasi rekayasa sistem informasi, audit
kode, dan deployment infrastruktur terpadu.
{t.office.description}
</p>
<div className="text-on-surface mt-2 flex flex-col gap-2 font-mono text-sm">
{offices.map((office) => (
@@ -581,169 +292,214 @@ export default function Clients() {
);
}
function DetailBlock({ label, text }: { label: string; text: string }) {
return (
<div className="bg-surface-container rounded-lg p-4">
<span className="text-primary mb-1 block font-mono text-[11px] font-bold uppercase">
{label}
</span>
<p className="text-on-surface-variant text-sm">{text}</p>
</div>
);
}
const PREVIEW_COUNT = 8;
function SectorPortfolio() {
const [filter, setFilter] = useState<Sector | 'all'>('all');
const visible = (sector: Sector) => filter === 'all' || filter === sector;
function SectorPortfolio({ t }: { t: Content }) {
const sectors: ProjectSector[] = ['government', 'private', 'soe'];
const [sector, setSector] = useState<ProjectSector>('government');
const [expanded, setExpanded] = useState(false);
const items = projectsBySector(sector);
const visible = expanded ? items : items.slice(0, PREVIEW_COUNT);
const selectSector = (next: ProjectSector) => {
setSector(next);
setExpanded(false);
};
return (
<Section tone="muted">
<div className="flex flex-col gap-12">
<SectionHeader
align="split"
eyebrow="Klasifikasi Sektor Portofolio"
title="Sektor Industri Teruji & Karakteristik Sistem"
eyebrow={t.portfolio.eyebrow}
title={t.portfolio.title}
aside={
<div
role="group"
aria-label="Filter sektor"
aria-label={t.portfolio.filterLabel}
className="border-outline-variant/40 bg-surface-container-low flex flex-wrap items-center gap-2 rounded-xl border p-1.5"
>
{filters.map((option) => (
{sectors.map((option) => (
<button
key={option.value}
key={option}
type="button"
aria-pressed={filter === option.value}
onClick={() => setFilter(option.value)}
aria-pressed={sector === option}
onClick={() => selectSector(option)}
className={cn(
'cursor-pointer rounded-lg px-4 py-2 text-xs font-semibold transition-all',
filter === option.value
sector === option
? 'bg-primary-container text-white shadow-md'
: 'bg-surface-container text-on-surface-variant hover:text-on-surface',
)}
>
{option.label}
{t.portfolio.sectors[option]} (
{projectsBySector(option).length})
</button>
))}
</div>
}
/>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{industrySectors.map((item) => (
<Card
key={item.code}
padding="lg"
interactive
className={cn(
'flex flex-col justify-between overflow-hidden',
item.wide && 'lg:col-span-2',
!visible(item.sector) && 'hidden',
)}
>
{item.wide && (
<Glow className="-top-12 -right-12 h-48 w-48 blur-3xl" />
)}
<div className="relative">
<div className="mb-6 flex items-center justify-between gap-3">
<span className="bg-surface-container text-primary inline-flex items-center gap-2 rounded-full px-3 py-1 font-mono text-[11px] font-semibold">
<p className="text-on-surface-variant -mt-6 max-w-2xl text-base">
{t.portfolio.description}
</p>
<Card padding="none" className="overflow-hidden">
<ul className="divide-outline-variant/30 divide-y">
{visible.map((project) => (
<li
key={`${project.title}-${project.client}-${project.year}`}
className="flex flex-col gap-2 p-5 sm:flex-row sm:items-center sm:gap-6 sm:px-6"
>
<span className="bg-surface-container text-primary w-fit shrink-0 rounded-lg px-3 py-1 font-mono text-sm font-bold">
{project.year}
</span>
<div className="flex flex-1 flex-col gap-1">
<span className="text-on-surface font-semibold">
{project.title}
</span>
<span className="text-on-surface-variant flex items-center gap-1.5 text-sm">
<Icon
name="apartment"
className="text-primary text-base"
/>
{project.client}
</span>
</div>
{project.program === 'erp' && (
<span className="border-primary/40 text-primary w-fit shrink-0 rounded-full border px-3 py-1 font-mono text-[11px] font-semibold">
{t.portfolio.erpBadge}
</span>
)}
</li>
))}
</ul>
</Card>
{items.length > PREVIEW_COUNT && (
<Button
variant="secondary"
size="sm"
icon={expanded ? 'expand_less' : 'expand_more'}
onClick={() => setExpanded((open) => !open)}
className="self-center"
>
{expanded
? t.portfolio.showLess
: t.portfolio.showAll.replace(
'{count}',
String(items.length),
)}
</Button>
)}
</div>
</Section>
);
}
const RELATED_PREVIEW = 4;
function FeaturedPrograms({ t }: { t: Content }) {
return (
<Section>
<div className="flex flex-col gap-12">
<SectionHeader
eyebrow={t.cases.eyebrow}
title={t.cases.title}
description={t.cases.description}
/>
<div className="grid grid-cols-1 gap-8 md:grid-cols-3">
{t.cases.items.map((item, index) => {
const related = projectsInProgram(item.program);
const remaining = related.length - RELATED_PREVIEW;
return (
<Card
key={item.program}
padding="none"
className="flex flex-col overflow-hidden"
>
<div className="bg-surface-container flex flex-col gap-3 p-6">
<div className="flex items-center justify-between">
<span className="text-primary font-mono text-xs font-bold">
{t.cases.label} 0{index + 1}
</span>
<Icon
name={item.icon}
className="text-sm"
className="text-on-surface-variant text-xl"
/>
{item.code}
</span>
<span className="text-on-surface-variant font-mono text-[11px] font-semibold">
{item.tag}
</div>
<h3 className="font-display text-on-surface text-lg leading-snug font-bold">
{item.title}
</h3>
<span className="text-highlight text-xs font-semibold">
{item.client}
</span>
</div>
<h3
className={cn(
'font-display text-on-surface mb-3 font-bold',
item.wide
? 'text-headline-md lg:text-headline-lg'
: 'text-headline-md',
)}
>
{item.title}
</h3>
<p className="text-on-surface-variant mb-6 text-base leading-relaxed">
{item.description}
</p>
<div
className={cn(
'mb-6 grid grid-cols-1 gap-4',
item.wide && 'sm:grid-cols-2',
)}
>
{item.details.map((detail) => (
<DetailBlock
key={detail.label}
{...detail}
/>
))}
<div className="flex flex-1 flex-col gap-5 p-6">
<p className="text-on-surface-variant text-sm leading-relaxed">
{item.summary}
</p>
<div className="grid grid-cols-2 gap-3">
<div className="bg-surface-container-high rounded-lg p-3">
<span className="font-display text-primary text-2xl font-bold">
{related.length}
</span>
<span className="text-on-surface-variant block text-xs font-semibold">
{t.cases.projects}
</span>
</div>
<div className="bg-surface-container-high flex items-center rounded-lg p-3">
<span className="font-display text-on-surface text-lg font-bold">
{yearRange(related)}
</span>
</div>
</div>
<div className="flex flex-col gap-2">
<span className="text-primary font-mono text-[11px] font-bold uppercase">
{t.cases.related}
</span>
<ul className="flex flex-col gap-2">
{related
.slice(0, RELATED_PREVIEW)
.map((project) => (
<li
key={`${project.title}-${project.year}`}
className="text-on-surface-variant flex gap-2 text-sm"
>
<span className="text-on-surface shrink-0 font-mono font-semibold">
{project.year}
</span>
<span>
{project.title}
</span>
</li>
))}
</ul>
{remaining > 0 && (
<span className="text-on-surface-variant text-xs italic">
{t.cases.more.replace(
'{count}',
String(remaining),
)}
</span>
)}
</div>
</div>
</div>
<div className="relative flex items-center justify-between gap-3 pt-2">
<span className="text-on-surface-variant font-mono text-xs">
{item.footnote}
</span>
<Icon
name="arrow_forward"
className="text-primary text-xl transition-transform group-hover:translate-x-2"
/>
</div>
</Card>
))}
<Card
padding="lg"
interactive
className={cn(
'flex flex-col items-start justify-between gap-6 md:col-span-2 md:flex-row md:items-center lg:col-span-3',
!visible('corporate') && 'hidden',
)}
>
<div className="max-w-3xl">
<span className="bg-surface-container text-primary mb-3 inline-flex items-center gap-2 rounded-full px-3 py-1 font-mono text-[11px] font-semibold">
<Icon name="storefront" className="text-sm" />
SEKTOR 05 // KOMERSIAL &amp; DISTRIBUSI
</span>
<h3 className="font-display text-headline-md text-on-surface mb-2 font-bold">
Sektor Komersial, Ritel Distribusi &amp;
Penyedia Jasa
</h3>
<p className="text-on-surface-variant text-base">
Multi-channel sales pipeline, quotation
bertingkat dengan otorisasi matriks harga,
automated customer invoicing, rekonsiliasi
perbankan otomatis, dan verifikasi batasan
kredit (credit limit) secara ketat dan otomatis.
</p>
</div>
<div className="flex shrink-0 flex-col items-start gap-2 md:items-end">
<span className="text-highlight font-mono text-[11px] font-bold uppercase">
Hasil Implementasi
</span>
<span className="text-headline-sm text-primary font-mono font-bold">
100% Real-time AR/AP
</span>
<span className="text-on-surface-variant text-sm">
Zero duplicate entry data
</span>
</div>
</Card>
</Card>
);
})}
</div>
</div>
</Section>
);
}
function RetentionGauge() {
function RetentionGauge({ t }: { t: Content }) {
return (
<div className="bg-surface-container flex w-full flex-col items-center justify-center rounded-xl p-6 lg:w-96">
<span className="text-on-surface-variant mb-4 font-mono text-[11px] font-semibold uppercase">
Indeks Kemitraan Berkelanjutan
{t.reliability.gaugeLabel}
</span>
<div className="relative flex h-48 w-48 items-center justify-center">
<svg
@@ -774,13 +530,12 @@ function RetentionGauge() {
99.8%
</span>
<span className="text-highlight text-xs font-semibold">
Tingkat Retensi
{t.reliability.gaugeCaption}
</span>
</div>
</div>
<p className="text-on-surface-variant mt-4 text-center text-sm">
Mayoritas mitra memperpanjang kontrak pemeliharaan dan audit
berkala melampaui siklus 5 tahunan.
{t.reliability.gaugeNote}
</p>
</div>
);