feat: implement help page with equal height cards
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
453
Dashboard-MD/BANTUAN.md
Normal file
453
Dashboard-MD/BANTUAN.md
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
Design Contract – Halaman Bantuan / Support Center
|
||||||
|
|
||||||
|
Dokumen ini adalah kontrak desain UI/UX untuk halaman Bantuan / Support Center.
|
||||||
|
Implementasi tidak dapat dilanjutkan tanpa mengikuti spesifikasi ini secara konsisten.
|
||||||
|
|
||||||
|
1. Tujuan Halaman
|
||||||
|
|
||||||
|
Halaman Bantuan bertujuan untuk:
|
||||||
|
|
||||||
|
Memberikan akses cepat ke panduan & dokumentasi
|
||||||
|
|
||||||
|
Menyediakan video tutorial
|
||||||
|
|
||||||
|
Menjawab pertanyaan umum (FAQ)
|
||||||
|
|
||||||
|
Menyediakan kontak support
|
||||||
|
|
||||||
|
Menyediakan virtual assistant (chat)
|
||||||
|
|
||||||
|
Menampilkan statistik kredibilitas platform
|
||||||
|
|
||||||
|
2. Struktur Layout Keseluruhan
|
||||||
|
Layout Grid
|
||||||
|
|
||||||
|
Menggunakan 3-column responsive grid.
|
||||||
|
|
||||||
|
Desktop (≥ 1200px)
|
||||||
|
|
||||||
|
Grid: 3 columns
|
||||||
|
|
||||||
|
Gap: 32px
|
||||||
|
|
||||||
|
Container max-width: 1200px – 1320px
|
||||||
|
|
||||||
|
Center aligned
|
||||||
|
|
||||||
|
Tablet (768px – 1199px)
|
||||||
|
|
||||||
|
Grid: 2 columns
|
||||||
|
|
||||||
|
Gap: 24px
|
||||||
|
|
||||||
|
Mobile (< 768px)
|
||||||
|
|
||||||
|
Grid: 1 column
|
||||||
|
|
||||||
|
Gap: 16px
|
||||||
|
|
||||||
|
Card full width
|
||||||
|
|
||||||
|
3. Struktur Komponen UI
|
||||||
|
3.1 Card Utama (Reusable Component)
|
||||||
|
|
||||||
|
Semua section menggunakan komponen dasar:
|
||||||
|
|
||||||
|
Card
|
||||||
|
├── Icon Container
|
||||||
|
├── Title
|
||||||
|
├── List / Content
|
||||||
|
|
||||||
|
Spesifikasi Card
|
||||||
|
|
||||||
|
Border radius: 16px
|
||||||
|
|
||||||
|
Padding: 24px
|
||||||
|
|
||||||
|
Shadow:
|
||||||
|
|
||||||
|
Light: soft shadow
|
||||||
|
|
||||||
|
Dark: subtle glow / low-opacity shadow
|
||||||
|
|
||||||
|
Transition hover: 0.2s ease
|
||||||
|
|
||||||
|
Hover effect:
|
||||||
|
|
||||||
|
Slight lift (translateY(-2px))
|
||||||
|
|
||||||
|
Elevation shadow increase
|
||||||
|
|
||||||
|
4. Daftar Komponen
|
||||||
|
4.1 Panduan Memulai
|
||||||
|
|
||||||
|
Isi:
|
||||||
|
|
||||||
|
Cara Login
|
||||||
|
|
||||||
|
Navigasi Dashboard
|
||||||
|
|
||||||
|
Fitur Dasar
|
||||||
|
|
||||||
|
Tips & Trik
|
||||||
|
|
||||||
|
Interaksi:
|
||||||
|
|
||||||
|
Klik item → navigasi ke halaman detail
|
||||||
|
|
||||||
|
Cursor pointer
|
||||||
|
|
||||||
|
Hover underline atau highlight
|
||||||
|
|
||||||
|
4.2 Video Tutorial
|
||||||
|
|
||||||
|
Isi:
|
||||||
|
|
||||||
|
Dashboard Overview
|
||||||
|
|
||||||
|
Analisis Data
|
||||||
|
|
||||||
|
Membuat Laporan
|
||||||
|
|
||||||
|
Export Data
|
||||||
|
|
||||||
|
Interaksi:
|
||||||
|
|
||||||
|
Klik → buka modal video atau halaman video
|
||||||
|
|
||||||
|
Bisa tambahkan icon play kecil di tiap item
|
||||||
|
|
||||||
|
4.3 FAQ
|
||||||
|
|
||||||
|
Isi:
|
||||||
|
|
||||||
|
Masalah Login
|
||||||
|
|
||||||
|
Reset Password
|
||||||
|
|
||||||
|
Akses Data
|
||||||
|
|
||||||
|
Laporan Error
|
||||||
|
|
||||||
|
Interaksi:
|
||||||
|
|
||||||
|
Accordion expand/collapse
|
||||||
|
|
||||||
|
Animasi height smooth (200–300ms)
|
||||||
|
|
||||||
|
4.4 Hubungi Support
|
||||||
|
|
||||||
|
Isi:
|
||||||
|
|
||||||
|
Email
|
||||||
|
|
||||||
|
WhatsApp
|
||||||
|
|
||||||
|
Jam Kerja
|
||||||
|
|
||||||
|
Waktu Respon
|
||||||
|
|
||||||
|
Interaksi:
|
||||||
|
|
||||||
|
Email → mailto link
|
||||||
|
|
||||||
|
WhatsApp → wa.me link
|
||||||
|
|
||||||
|
Jam kerja non-clickable
|
||||||
|
|
||||||
|
4.5 Dokumentasi
|
||||||
|
|
||||||
|
Isi:
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
|
||||||
|
Integrasi Sistem
|
||||||
|
|
||||||
|
Format Data
|
||||||
|
|
||||||
|
Best Practices
|
||||||
|
|
||||||
|
Interaksi:
|
||||||
|
|
||||||
|
Klik → navigasi dokumentasi
|
||||||
|
|
||||||
|
4.6 Jenna – Virtual Assistant
|
||||||
|
|
||||||
|
Komponen:
|
||||||
|
|
||||||
|
Chat Container
|
||||||
|
├── Header Title
|
||||||
|
├── Chat Message Area
|
||||||
|
├── Input Field
|
||||||
|
└── Send Button
|
||||||
|
|
||||||
|
|
||||||
|
Spesifikasi:
|
||||||
|
|
||||||
|
Tinggi tetap (±300–350px)
|
||||||
|
|
||||||
|
Scrollable message container
|
||||||
|
|
||||||
|
Input rounded
|
||||||
|
|
||||||
|
Send button icon (arrow)
|
||||||
|
|
||||||
|
Interaksi:
|
||||||
|
|
||||||
|
Enter → kirim pesan
|
||||||
|
|
||||||
|
Klik send → kirim pesan
|
||||||
|
|
||||||
|
Auto-scroll ke pesan terakhir
|
||||||
|
|
||||||
|
Disabled state saat loading
|
||||||
|
|
||||||
|
4.7 Statistik Section
|
||||||
|
|
||||||
|
3 Card horizontal:
|
||||||
|
|
||||||
|
150+ Artikel Panduan
|
||||||
|
|
||||||
|
50+ Video Tutorial
|
||||||
|
|
||||||
|
24/7 Support Aktif
|
||||||
|
|
||||||
|
Spesifikasi:
|
||||||
|
|
||||||
|
Center aligned text
|
||||||
|
|
||||||
|
Angka besar (font-size 32–40px)
|
||||||
|
|
||||||
|
Subtext kecil opacity 70%
|
||||||
|
|
||||||
|
5. Design System
|
||||||
|
5.1 Light Mode
|
||||||
|
Background
|
||||||
|
|
||||||
|
Page background: #F5F7FA
|
||||||
|
|
||||||
|
Card background: #FFFFFF
|
||||||
|
|
||||||
|
Primary Color
|
||||||
|
|
||||||
|
Blue: #3B82F6
|
||||||
|
|
||||||
|
Hover: #2563EB
|
||||||
|
|
||||||
|
Text
|
||||||
|
|
||||||
|
Primary: #111827
|
||||||
|
|
||||||
|
Secondary: #6B7280
|
||||||
|
|
||||||
|
Border
|
||||||
|
|
||||||
|
#E5E7EB
|
||||||
|
|
||||||
|
Shadow
|
||||||
|
0 4px 12px rgba(0,0,0,0.05)
|
||||||
|
|
||||||
|
Icon Container
|
||||||
|
|
||||||
|
Background: #EFF6FF
|
||||||
|
|
||||||
|
Icon color: #2563EB
|
||||||
|
|
||||||
|
5.2 Dark Mode
|
||||||
|
Background
|
||||||
|
|
||||||
|
Page background: #0F172A
|
||||||
|
|
||||||
|
Card background: #1E293B
|
||||||
|
|
||||||
|
Primary Color
|
||||||
|
|
||||||
|
Blue: #3B82F6
|
||||||
|
|
||||||
|
Hover: #60A5FA
|
||||||
|
|
||||||
|
Text
|
||||||
|
|
||||||
|
Primary: #F8FAFC
|
||||||
|
|
||||||
|
Secondary: #94A3B8
|
||||||
|
|
||||||
|
Border
|
||||||
|
|
||||||
|
#334155
|
||||||
|
|
||||||
|
Shadow
|
||||||
|
0 4px 20px rgba(0,0,0,0.4)
|
||||||
|
|
||||||
|
Icon Container
|
||||||
|
|
||||||
|
Background: #1D4ED8
|
||||||
|
|
||||||
|
Icon color: #FFFFFF
|
||||||
|
|
||||||
|
6. Typography
|
||||||
|
|
||||||
|
Font Family:
|
||||||
|
|
||||||
|
Inter / Poppins / System UI
|
||||||
|
|
||||||
|
Hierarchy:
|
||||||
|
|
||||||
|
Element Size Weight
|
||||||
|
Section Title 18–20px 600
|
||||||
|
Card Title 16–18px 600
|
||||||
|
List Item 14–16px 400
|
||||||
|
Statistik Number 32–40px 700
|
||||||
|
|
||||||
|
Line height:
|
||||||
|
|
||||||
|
1.5 standard
|
||||||
|
|
||||||
|
1.2 for large numbers
|
||||||
|
|
||||||
|
7. Spacing System
|
||||||
|
|
||||||
|
Gunakan sistem 8pt grid:
|
||||||
|
|
||||||
|
8px
|
||||||
|
|
||||||
|
16px
|
||||||
|
|
||||||
|
24px
|
||||||
|
|
||||||
|
32px
|
||||||
|
|
||||||
|
48px
|
||||||
|
|
||||||
|
Padding Card: 24px
|
||||||
|
Gap Grid Desktop: 32px
|
||||||
|
|
||||||
|
8. Responsivitas
|
||||||
|
Desktop
|
||||||
|
|
||||||
|
3 kolom utama
|
||||||
|
|
||||||
|
Statistik 3 sejajar
|
||||||
|
|
||||||
|
Tablet
|
||||||
|
|
||||||
|
2 kolom
|
||||||
|
|
||||||
|
Statistik 2 + 1
|
||||||
|
|
||||||
|
Mobile
|
||||||
|
|
||||||
|
1 kolom
|
||||||
|
|
||||||
|
Statistik stacked vertical
|
||||||
|
|
||||||
|
Chat full width
|
||||||
|
|
||||||
|
9. State & Interactivity Requirements
|
||||||
|
|
||||||
|
Harus tersedia:
|
||||||
|
|
||||||
|
Hover state
|
||||||
|
|
||||||
|
Active state
|
||||||
|
|
||||||
|
Focus state (accessibility)
|
||||||
|
|
||||||
|
Disabled state
|
||||||
|
|
||||||
|
Loading state (chat)
|
||||||
|
|
||||||
|
Keyboard support:
|
||||||
|
|
||||||
|
Tab navigable
|
||||||
|
|
||||||
|
Enter kirim pesan
|
||||||
|
|
||||||
|
Esc tutup modal (jika ada)
|
||||||
|
|
||||||
|
10. Accessibility
|
||||||
|
|
||||||
|
Minimum contrast ratio 4.5:1
|
||||||
|
|
||||||
|
Focus ring visible
|
||||||
|
|
||||||
|
Button min-height 40px
|
||||||
|
|
||||||
|
Click area minimal 44x44px
|
||||||
|
|
||||||
|
11. Animasi
|
||||||
|
|
||||||
|
Durasi standar: 200ms – 300ms
|
||||||
|
Easing: ease-in-out
|
||||||
|
|
||||||
|
Digunakan untuk:
|
||||||
|
|
||||||
|
Hover card
|
||||||
|
|
||||||
|
Accordion FAQ
|
||||||
|
|
||||||
|
Chat message appear
|
||||||
|
|
||||||
|
Button press
|
||||||
|
|
||||||
|
12. Toggle Dark / Light Mode
|
||||||
|
|
||||||
|
Harus tersedia:
|
||||||
|
|
||||||
|
Theme switcher
|
||||||
|
|
||||||
|
Persist ke localStorage
|
||||||
|
|
||||||
|
Default mengikuti system preference
|
||||||
|
|
||||||
|
13. Data Dinamis
|
||||||
|
|
||||||
|
Data yang harus bisa dinamis:
|
||||||
|
|
||||||
|
Jumlah artikel
|
||||||
|
|
||||||
|
Jumlah video
|
||||||
|
|
||||||
|
Status support 24/7
|
||||||
|
|
||||||
|
Chat message list
|
||||||
|
|
||||||
|
FAQ content
|
||||||
|
|
||||||
|
Dokumentasi link
|
||||||
|
|
||||||
|
14. Non-Functional Requirements
|
||||||
|
|
||||||
|
Clean modular component
|
||||||
|
|
||||||
|
Reusable Card component
|
||||||
|
|
||||||
|
Maintainable theme config
|
||||||
|
|
||||||
|
Dark & Light share same structure
|
||||||
|
|
||||||
|
15. Kesimpulan
|
||||||
|
|
||||||
|
Halaman ini menggunakan:
|
||||||
|
|
||||||
|
Card-based layout
|
||||||
|
|
||||||
|
Grid responsive
|
||||||
|
|
||||||
|
Dual theme (Light & Dark)
|
||||||
|
|
||||||
|
High clarity & readability
|
||||||
|
|
||||||
|
Modern SaaS style
|
||||||
|
|
||||||
|
Virtual assistant as engagement point
|
||||||
|
|
||||||
|
Implementasi wajib mengikuti spesifikasi ini agar:
|
||||||
|
|
||||||
|
Konsistensi visual terjaga
|
||||||
|
|
||||||
|
User experience optimal
|
||||||
|
|
||||||
|
Maintainability tinggi
|
||||||
|
|
||||||
|
Skalabilitas mudah
|
||||||
246
src/components/help-page.tsx
Normal file
246
src/components/help-page.tsx
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
import { Container, Grid, Title, Text, SimpleGrid, Box, Accordion, Stack } from '@mantine/core';
|
||||||
|
import { HelpCard } from '@/components/ui/help-card';
|
||||||
|
import { IconBook, IconVideo, IconHelpCircle, IconMessage, IconFileText, IconHeadphones } from '@tabler/icons-react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const HelpPage = () => {
|
||||||
|
// Sample data for sections
|
||||||
|
const guideItems = [
|
||||||
|
{ title: 'Cara Login', description: 'Langkah-langkah untuk login ke dashboard' },
|
||||||
|
{ title: 'Navigasi Dashboard', description: 'Penjelasan tentang tata letak dan navigasi' },
|
||||||
|
{ title: 'Fitur Dasar', description: 'Panduan penggunaan fitur-fitur utama' },
|
||||||
|
{ title: 'Tips & Trik', description: 'Tips untuk meningkatkan produktivitas' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const videoItems = [
|
||||||
|
{ title: 'Dashboard Overview', duration: '5:23' },
|
||||||
|
{ title: 'Analisis Data', duration: '8:45' },
|
||||||
|
{ title: 'Membuat Laporan', duration: '6:12' },
|
||||||
|
{ title: 'Export Data', duration: '4:30' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const faqItems = [
|
||||||
|
{ question: 'Bagaimana cara reset password?', answer: 'Anda dapat mereset password melalui halaman login dengan klik "Lupa Password"' },
|
||||||
|
{ question: 'Apakah saya bisa mengakses data offline?', answer: 'Saat ini aplikasi hanya dapat diakses secara online' },
|
||||||
|
{ question: 'Berapa lama waktu respon support?', answer: 'Tim support kami biasanya merespon dalam waktu kurang dari 24 jam' },
|
||||||
|
{ question: 'Bagaimana cara menambahkan pengguna baru?', answer: 'Fitur penambahan pengguna dapat ditemukan di menu Pengaturan > Manajemen Pengguna' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const documentationItems = [
|
||||||
|
{ title: 'API Reference', description: 'Dokumentasi lengkap untuk integrasi API' },
|
||||||
|
{ title: 'Integrasi Sistem', description: 'Cara mengintegrasikan dengan sistem eksternal' },
|
||||||
|
{ title: 'Format Data', description: 'Spesifikasi format data yang didukung' },
|
||||||
|
{ title: 'Best Practices', description: 'Praktik terbaik dalam penggunaan platform' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ value: '150+', label: 'Artikel Panduan' },
|
||||||
|
{ value: '50+', label: 'Video Tutorial' },
|
||||||
|
{ value: '24/7', label: 'Support Aktif' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// State for chat functionality
|
||||||
|
const [messages, setMessages] = useState([
|
||||||
|
{ id: 1, text: 'Halo! Saya Jenna, asisten virtual Anda. Bagaimana saya bisa membantu hari ini?', sender: 'jenna' }
|
||||||
|
]);
|
||||||
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleSendMessage = () => {
|
||||||
|
if (inputValue.trim() === '') return;
|
||||||
|
|
||||||
|
// Add user message
|
||||||
|
const newUserMessage = {
|
||||||
|
id: messages.length + 1,
|
||||||
|
text: inputValue,
|
||||||
|
sender: 'user'
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, newUserMessage]);
|
||||||
|
setInputValue('');
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
// Simulate Jenna's response after delay
|
||||||
|
setTimeout(() => {
|
||||||
|
const jennaResponse = {
|
||||||
|
id: messages.length + 2,
|
||||||
|
text: 'Terima kasih atas pertanyaan Anda. Saat ini saya adalah versi awal dari asisten virtual. Tim kami sedang mengembangkan kemampuan saya lebih lanjut.',
|
||||||
|
sender: 'jenna'
|
||||||
|
};
|
||||||
|
setMessages(prev => [...prev, jennaResponse]);
|
||||||
|
setIsLoading(false);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyPress = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter' && !e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSendMessage();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container size="lg" py="xl">
|
||||||
|
<Title order={1} mb="xl" ta="center">Pusat Bantuan</Title>
|
||||||
|
<Text size="lg" color="dimmed" ta="center" mb="xl">
|
||||||
|
Temukan jawaban untuk pertanyaan Anda atau hubungi tim support kami
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{/* Statistics Section */}
|
||||||
|
<SimpleGrid cols={3} spacing="lg" mb="xl">
|
||||||
|
{stats.map((stat, index) => (
|
||||||
|
<HelpCard key={index} p="lg" style={{ textAlign: 'center' }} h="100%">
|
||||||
|
<Text size="xl" fw={700} style={{ fontSize: '32px' }}>{stat.value}</Text>
|
||||||
|
<Text size="sm" color="dimmed">{stat.label}</Text>
|
||||||
|
</HelpCard>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
|
||||||
|
<Stack gap="lg">
|
||||||
|
<Box>
|
||||||
|
<Grid gutter="lg" justify="center">
|
||||||
|
{/* Panduan Memulai */}
|
||||||
|
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
|
||||||
|
<HelpCard icon={<IconBook size={24} />} title="Panduan Memulai" h="100%">
|
||||||
|
<Box>
|
||||||
|
{guideItems.map((item, index) => (
|
||||||
|
<Box key={index} py="sm" style={{ borderBottom: '1px solid #eee', cursor: 'pointer' }} onClick={() => alert(`Navigasi ke ${item.title}`)}>
|
||||||
|
<Text fw={500}>{item.title}</Text>
|
||||||
|
<Text size="sm" color="dimmed">{item.description}</Text>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</HelpCard>
|
||||||
|
</Grid.Col>
|
||||||
|
|
||||||
|
{/* Video Tutorial */}
|
||||||
|
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
|
||||||
|
<HelpCard icon={<IconVideo size={24} />} title="Video Tutorial" h="100%">
|
||||||
|
<Box>
|
||||||
|
{videoItems.map((item, index) => (
|
||||||
|
<Box key={index} py="sm" style={{ borderBottom: '1px solid #eee', cursor: 'pointer' }} onClick={() => alert(`Buka video: ${item.title}`)}>
|
||||||
|
<Text fw={500}>{item.title}</Text>
|
||||||
|
<Text size="sm" color="dimmed">{item.duration}</Text>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</HelpCard>
|
||||||
|
</Grid.Col>
|
||||||
|
|
||||||
|
{/* FAQ */}
|
||||||
|
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
|
||||||
|
<HelpCard icon={<IconHelpCircle size={24} />} title="FAQ" h="100%">
|
||||||
|
<Accordion variant="separated">
|
||||||
|
{faqItems.map((item, index) => (
|
||||||
|
<Accordion.Item key={index} value={`faq-${index}`}>
|
||||||
|
<Accordion.Control>{item.question}</Accordion.Control>
|
||||||
|
<Accordion.Panel>
|
||||||
|
<Text size="sm">{item.answer}</Text>
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
))}
|
||||||
|
</Accordion>
|
||||||
|
</HelpCard>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Grid>
|
||||||
|
{/* Hubungi Support */}
|
||||||
|
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
|
||||||
|
<HelpCard icon={<IconHeadphones size={24} />} title="Hubungi Support" h="100%">
|
||||||
|
<Box>
|
||||||
|
<Text fw={500}>Email</Text>
|
||||||
|
<Text size="sm" color="dimmed" mb="md"><a href="mailto:support@example.com">support@example.com</a></Text>
|
||||||
|
|
||||||
|
<Text fw={500}>WhatsApp</Text>
|
||||||
|
<Text size="sm" color="dimmed" mb="md"><a href="https://wa.me/1234567890">+62 123 456 7890</a></Text>
|
||||||
|
|
||||||
|
<Text fw={500}>Jam Kerja</Text>
|
||||||
|
<Text size="sm" color="dimmed">Senin - Jumat, 09:00 - 17:00 WIB</Text>
|
||||||
|
|
||||||
|
<Text fw={500} mt="md">Waktu Respon</Text>
|
||||||
|
<Text size="sm" color="dimmed">Rata-rata 2-4 jam kerja</Text>
|
||||||
|
</Box>
|
||||||
|
</HelpCard>
|
||||||
|
</Grid.Col>
|
||||||
|
|
||||||
|
{/* Dokumentasi */}
|
||||||
|
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
|
||||||
|
<HelpCard icon={<IconFileText size={24} />} title="Dokumentasi" h="100%">
|
||||||
|
<Box>
|
||||||
|
{documentationItems.map((item, index) => (
|
||||||
|
<Box key={index} py="sm" style={{ borderBottom: '1px solid #eee', cursor: 'pointer' }} onClick={() => alert(`Navigasi ke dokumentasi: ${item.title}`)}>
|
||||||
|
<Text fw={500}>{item.title}</Text>
|
||||||
|
<Text size="sm" color="dimmed">{item.description}</Text>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</HelpCard>
|
||||||
|
</Grid.Col>
|
||||||
|
|
||||||
|
{/* Jenna - Virtual Assistant */}
|
||||||
|
<Grid.Col span={{ base: 12, sm: 6, md: 4 }}>
|
||||||
|
<HelpCard icon={<IconMessage size={24} />} title="Jenna - Virtual Assistant" h="100%">
|
||||||
|
<Box style={{ height: '300px', display: 'flex', flexDirection: 'column' }}>
|
||||||
|
<Box style={{ flex: 1, overflowY: 'auto', marginBottom: '12px', maxHeight: '200px' }}>
|
||||||
|
{messages.map((msg) => (
|
||||||
|
<Box
|
||||||
|
key={msg.id}
|
||||||
|
style={{
|
||||||
|
alignSelf: msg.sender === 'user' ? 'flex-end' : 'flex-start',
|
||||||
|
backgroundColor: msg.sender === 'user' ? '#3B82F6' : '#F3F4F6',
|
||||||
|
color: msg.sender === 'user' ? 'white' : 'black',
|
||||||
|
padding: '8px 12px',
|
||||||
|
borderRadius: '8px',
|
||||||
|
marginBottom: '8px',
|
||||||
|
maxWidth: '80%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{msg.text}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box style={{ display: 'flex', gap: '8px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
|
onKeyPress={handleKeyPress}
|
||||||
|
placeholder="Ketik pesan Anda..."
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
padding: '8px 12px',
|
||||||
|
borderRadius: '20px',
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
}}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleSendMessage}
|
||||||
|
disabled={isLoading || inputValue.trim() === ''}
|
||||||
|
style={{
|
||||||
|
padding: '8px 16px',
|
||||||
|
borderRadius: '20px',
|
||||||
|
backgroundColor: '#3B82F6',
|
||||||
|
color: 'white',
|
||||||
|
border: 'none',
|
||||||
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</HelpCard>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HelpPage;
|
||||||
90
src/components/ui/help-card.tsx
Normal file
90
src/components/ui/help-card.tsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { Card, useMantineTheme, useComputedColorScheme } from '@mantine/core';
|
||||||
|
import type { CardProps } from '@mantine/core';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface HelpCardProps extends CardProps {
|
||||||
|
children: ReactNode;
|
||||||
|
icon?: ReactNode;
|
||||||
|
title?: string;
|
||||||
|
minHeight?: string | number; // Allow specifying a minimum height
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HelpCard = ({
|
||||||
|
children,
|
||||||
|
icon,
|
||||||
|
title,
|
||||||
|
minHeight = 'auto', // Default to auto, but allow override
|
||||||
|
...props
|
||||||
|
}: HelpCardProps) => {
|
||||||
|
const theme = useMantineTheme();
|
||||||
|
const colorScheme = useComputedColorScheme('light');
|
||||||
|
const isDark = colorScheme === 'dark';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
shadow="sm"
|
||||||
|
padding="xl"
|
||||||
|
radius="md"
|
||||||
|
withBorder
|
||||||
|
style={{
|
||||||
|
backgroundColor: isDark ? theme.colors.dark[7] : theme.white,
|
||||||
|
borderRadius: '16px',
|
||||||
|
transition: 'transform 0.2s ease, box-shadow 0.2s ease',
|
||||||
|
border: `1px solid ${
|
||||||
|
isDark ? theme.colors.dark[4] : theme.colors.gray[3]
|
||||||
|
}`,
|
||||||
|
minHeight, // Apply the minimum height
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{(icon || title) && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '12px',
|
||||||
|
marginBottom: '16px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: isDark
|
||||||
|
? theme.colors.blue[8]
|
||||||
|
: theme.colors.blue[0],
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '8px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{title && (
|
||||||
|
<h3
|
||||||
|
style={{
|
||||||
|
margin: 0,
|
||||||
|
fontSize: '16px',
|
||||||
|
fontWeight: 600,
|
||||||
|
color: isDark
|
||||||
|
? theme.colors.dark[0]
|
||||||
|
: theme.colors.dark[9],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -28,6 +28,7 @@ import { Route as DashboardKeamananRouteImport } from './routes/dashboard/keaman
|
|||||||
import { Route as DashboardJennaAnalyticRouteImport } from './routes/dashboard/jenna-analytic'
|
import { Route as DashboardJennaAnalyticRouteImport } from './routes/dashboard/jenna-analytic'
|
||||||
import { Route as DashboardDemografiPekerjaanRouteImport } from './routes/dashboard/demografi-pekerjaan'
|
import { Route as DashboardDemografiPekerjaanRouteImport } from './routes/dashboard/demografi-pekerjaan'
|
||||||
import { Route as DashboardBumdesRouteImport } from './routes/dashboard/bumdes'
|
import { Route as DashboardBumdesRouteImport } from './routes/dashboard/bumdes'
|
||||||
|
import { Route as DashboardBantuanRouteImport } from './routes/dashboard/bantuan'
|
||||||
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
||||||
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
||||||
import { Route as AdminApikeyRouteImport } from './routes/admin/apikey'
|
import { Route as AdminApikeyRouteImport } from './routes/admin/apikey'
|
||||||
@@ -130,6 +131,11 @@ const DashboardBumdesRoute = DashboardBumdesRouteImport.update({
|
|||||||
path: '/bumdes',
|
path: '/bumdes',
|
||||||
getParentRoute: () => DashboardRouteRoute,
|
getParentRoute: () => DashboardRouteRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const DashboardBantuanRoute = DashboardBantuanRouteImport.update({
|
||||||
|
id: '/bantuan',
|
||||||
|
path: '/bantuan',
|
||||||
|
getParentRoute: () => DashboardRouteRoute,
|
||||||
|
} as any)
|
||||||
const AdminUsersRoute = AdminUsersRouteImport.update({
|
const AdminUsersRoute = AdminUsersRouteImport.update({
|
||||||
id: '/users',
|
id: '/users',
|
||||||
path: '/users',
|
path: '/users',
|
||||||
@@ -155,6 +161,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/admin/apikey': typeof AdminApikeyRoute
|
'/admin/apikey': typeof AdminApikeyRoute
|
||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
|
'/dashboard/bantuan': typeof DashboardBantuanRoute
|
||||||
'/dashboard/bumdes': typeof DashboardBumdesRoute
|
'/dashboard/bumdes': typeof DashboardBumdesRoute
|
||||||
'/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute
|
'/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute
|
||||||
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
||||||
@@ -177,6 +184,7 @@ export interface FileRoutesByTo {
|
|||||||
'/admin/apikey': typeof AdminApikeyRoute
|
'/admin/apikey': typeof AdminApikeyRoute
|
||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
|
'/dashboard/bantuan': typeof DashboardBantuanRoute
|
||||||
'/dashboard/bumdes': typeof DashboardBumdesRoute
|
'/dashboard/bumdes': typeof DashboardBumdesRoute
|
||||||
'/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute
|
'/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute
|
||||||
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
||||||
@@ -202,6 +210,7 @@ export interface FileRoutesById {
|
|||||||
'/admin/apikey': typeof AdminApikeyRoute
|
'/admin/apikey': typeof AdminApikeyRoute
|
||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
|
'/dashboard/bantuan': typeof DashboardBantuanRoute
|
||||||
'/dashboard/bumdes': typeof DashboardBumdesRoute
|
'/dashboard/bumdes': typeof DashboardBumdesRoute
|
||||||
'/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute
|
'/dashboard/demografi-pekerjaan': typeof DashboardDemografiPekerjaanRoute
|
||||||
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
'/dashboard/jenna-analytic': typeof DashboardJennaAnalyticRoute
|
||||||
@@ -228,6 +237,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/apikey'
|
| '/admin/apikey'
|
||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
|
| '/dashboard/bantuan'
|
||||||
| '/dashboard/bumdes'
|
| '/dashboard/bumdes'
|
||||||
| '/dashboard/demografi-pekerjaan'
|
| '/dashboard/demografi-pekerjaan'
|
||||||
| '/dashboard/jenna-analytic'
|
| '/dashboard/jenna-analytic'
|
||||||
@@ -250,6 +260,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/apikey'
|
| '/admin/apikey'
|
||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
|
| '/dashboard/bantuan'
|
||||||
| '/dashboard/bumdes'
|
| '/dashboard/bumdes'
|
||||||
| '/dashboard/demografi-pekerjaan'
|
| '/dashboard/demografi-pekerjaan'
|
||||||
| '/dashboard/jenna-analytic'
|
| '/dashboard/jenna-analytic'
|
||||||
@@ -274,6 +285,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/apikey'
|
| '/admin/apikey'
|
||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
|
| '/dashboard/bantuan'
|
||||||
| '/dashboard/bumdes'
|
| '/dashboard/bumdes'
|
||||||
| '/dashboard/demografi-pekerjaan'
|
| '/dashboard/demografi-pekerjaan'
|
||||||
| '/dashboard/jenna-analytic'
|
| '/dashboard/jenna-analytic'
|
||||||
@@ -437,6 +449,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof DashboardBumdesRouteImport
|
preLoaderRoute: typeof DashboardBumdesRouteImport
|
||||||
parentRoute: typeof DashboardRouteRoute
|
parentRoute: typeof DashboardRouteRoute
|
||||||
}
|
}
|
||||||
|
'/dashboard/bantuan': {
|
||||||
|
id: '/dashboard/bantuan'
|
||||||
|
path: '/bantuan'
|
||||||
|
fullPath: '/dashboard/bantuan'
|
||||||
|
preLoaderRoute: typeof DashboardBantuanRouteImport
|
||||||
|
parentRoute: typeof DashboardRouteRoute
|
||||||
|
}
|
||||||
'/admin/users': {
|
'/admin/users': {
|
||||||
id: '/admin/users'
|
id: '/admin/users'
|
||||||
path: '/users'
|
path: '/users'
|
||||||
@@ -480,6 +499,7 @@ const AdminRouteRouteWithChildren = AdminRouteRoute._addFileChildren(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface DashboardRouteRouteChildren {
|
interface DashboardRouteRouteChildren {
|
||||||
|
DashboardBantuanRoute: typeof DashboardBantuanRoute
|
||||||
DashboardBumdesRoute: typeof DashboardBumdesRoute
|
DashboardBumdesRoute: typeof DashboardBumdesRoute
|
||||||
DashboardDemografiPekerjaanRoute: typeof DashboardDemografiPekerjaanRoute
|
DashboardDemografiPekerjaanRoute: typeof DashboardDemografiPekerjaanRoute
|
||||||
DashboardJennaAnalyticRoute: typeof DashboardJennaAnalyticRoute
|
DashboardJennaAnalyticRoute: typeof DashboardJennaAnalyticRoute
|
||||||
@@ -492,6 +512,7 @@ interface DashboardRouteRouteChildren {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DashboardRouteRouteChildren: DashboardRouteRouteChildren = {
|
const DashboardRouteRouteChildren: DashboardRouteRouteChildren = {
|
||||||
|
DashboardBantuanRoute: DashboardBantuanRoute,
|
||||||
DashboardBumdesRoute: DashboardBumdesRoute,
|
DashboardBumdesRoute: DashboardBumdesRoute,
|
||||||
DashboardDemografiPekerjaanRoute: DashboardDemografiPekerjaanRoute,
|
DashboardDemografiPekerjaanRoute: DashboardDemografiPekerjaanRoute,
|
||||||
DashboardJennaAnalyticRoute: DashboardJennaAnalyticRoute,
|
DashboardJennaAnalyticRoute: DashboardJennaAnalyticRoute,
|
||||||
|
|||||||
7
src/routes/dashboard/bantuan.ts
Normal file
7
src/routes/dashboard/bantuan.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
import HelpPage from '@/components/help-page'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/dashboard/bantuan')({
|
||||||
|
component: HelpPage,
|
||||||
|
})
|
||||||
|
|
||||||
Reference in New Issue
Block a user