wepee commited on
Commit
f98535e
·
1 Parent(s): 0c0f5cc

fix: priority 4,3,2

Browse files
resources/js/components/auth/register-role-form.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { Head, Link } from '@inertiajs/react';
2
  import type { FormEvent } from 'react';
3
  import { useState } from 'react';
4
 
@@ -9,7 +9,7 @@ import { Input } from '@/components/ui/input';
9
  import { Label } from '@/components/ui/label';
10
  import { Spinner } from '@/components/ui/spinner';
11
  import { RagApiError, registerUser } from '@/lib/rag-client';
12
- import { register } from '@/routes';
13
 
14
  const roleContent = {
15
  mahasiswa: {
@@ -91,9 +91,13 @@ function validateRegisterForm(
91
  }
92
 
93
  if (!normalizedIdentityNumber) {
94
- errors.identity_number = `${identifierLabel} wajib diisi.`;
95
- } else if (!identityNumberPattern.test(normalizedIdentityNumber)) {
96
- errors.identity_number = `${identifierLabel} hanya boleh angka.`;
 
 
 
 
97
  }
98
 
99
  if (!normalizedEmail) {
@@ -311,7 +315,8 @@ export default function RegisterRoleForm({ role }: RegisterRoleFormProps) {
311
  setFieldErrors({});
312
  setFormValues(emptyFormValues);
313
  setTouchedFields({});
314
- setSuccessMessage('Registrasi berhasil. Silakan login.');
 
315
  } catch (err) {
316
  if (err instanceof RagApiError) {
317
  const parsed = parseRegisterApiError(err);
 
1
+ import { Head, Link, router } from '@inertiajs/react';
2
  import type { FormEvent } from 'react';
3
  import { useState } from 'react';
4
 
 
9
  import { Label } from '@/components/ui/label';
10
  import { Spinner } from '@/components/ui/spinner';
11
  import { RagApiError, registerUser } from '@/lib/rag-client';
12
+ import { login, register } from '@/routes';
13
 
14
  const roleContent = {
15
  mahasiswa: {
 
91
  }
92
 
93
  if (!normalizedIdentityNumber) {
94
+ errors.identity_number = `${identifierLabel} wajib diisi`;
95
+ } else if (!/^\d+$/.test(normalizedIdentityNumber)) {
96
+ errors.identity_number = `${identifierLabel} hanya boleh angka`;
97
+ } else if (normalizedIdentityNumber.length < 5) {
98
+ errors.identity_number = `${identifierLabel} minimal 5 digit`;
99
+ } else if (normalizedIdentityNumber.length > 30) {
100
+ errors.identity_number = `${identifierLabel} maksimal 30 digit`;
101
  }
102
 
103
  if (!normalizedEmail) {
 
315
  setFieldErrors({});
316
  setFormValues(emptyFormValues);
317
  setTouchedFields({});
318
+ setSuccessMessage('Registrasi berhasil! Mengalihkan ke halaman login...');
319
+ setTimeout(() => router.visit(login()), 2000);
320
  } catch (err) {
321
  if (err instanceof RagApiError) {
322
  const parsed = parseRegisterApiError(err);
resources/js/components/student/student-shell.tsx CHANGED
@@ -157,7 +157,7 @@ function StudentSidebar({
157
  const [isLogoutDialogOpen, setIsLogoutDialogOpen] = useState(false);
158
  const [sessionToDelete, setSessionToDelete] =
159
  useState<ChatSessionResponse>();
160
- const { state } = useSidebar();
161
  const isSidebarCollapsed = state === 'collapsed';
162
 
163
  function handleDeleteDialogOpenChange(open: boolean): void {
@@ -211,6 +211,10 @@ function StudentSidebar({
211
  <SidebarMenuButton
212
  className="student-history-menu-button"
213
  tooltip="Riwayat Chat"
 
 
 
 
214
  >
215
  <Clock3 className="student-history-menu-icon size-4" />
216
  <span className="student-history-copy">
@@ -508,6 +512,7 @@ export function StudentShell({
508
 
509
  <SidebarInset className="student-workspace">
510
  <header className="student-topbar">
 
511
  <h1 className="student-brand-title">RAG Hub</h1>
512
 
513
  <div className="student-topbar-actions">
 
157
  const [isLogoutDialogOpen, setIsLogoutDialogOpen] = useState(false);
158
  const [sessionToDelete, setSessionToDelete] =
159
  useState<ChatSessionResponse>();
160
+ const { state, toggleSidebar } = useSidebar();
161
  const isSidebarCollapsed = state === 'collapsed';
162
 
163
  function handleDeleteDialogOpenChange(open: boolean): void {
 
211
  <SidebarMenuButton
212
  className="student-history-menu-button"
213
  tooltip="Riwayat Chat"
214
+ onClick={() => {
215
+ toggleSidebar();
216
+ setIsHistoryOpen(true);
217
+ }}
218
  >
219
  <Clock3 className="student-history-menu-icon size-4" />
220
  <span className="student-history-copy">
 
512
 
513
  <SidebarInset className="student-workspace">
514
  <header className="student-topbar">
515
+ <SidebarTrigger className="md:hidden" />
516
  <h1 className="student-brand-title">RAG Hub</h1>
517
 
518
  <div className="student-topbar-actions">
resources/js/pages/dosen.tsx CHANGED
@@ -1,6 +1,6 @@
1
  import { Head, router } from '@inertiajs/react';
2
  import type { LucideIcon } from 'lucide-react';
3
- import { AlertTriangle, Database, FileText, Plus, Search } from 'lucide-react';
4
  import type { FormEvent, ReactNode } from 'react';
5
  import { useEffect, useMemo, useState } from 'react';
6
 
@@ -19,6 +19,12 @@ import {
19
  import { Input } from '@/components/ui/input';
20
  import { Label } from '@/components/ui/label';
21
  import { LoadingIndicator } from '@/components/ui/loading-indicator';
 
 
 
 
 
 
22
  import {
23
  createCourse,
24
  listCourseDocuments,
@@ -41,6 +47,7 @@ type Metric = {
41
  label: string;
42
  value: ReactNode;
43
  description?: string;
 
44
  icon: LucideIcon;
45
  tone: 'primary' | 'danger';
46
  };
@@ -103,7 +110,21 @@ function MetricCard({ metric }: { metric: Metric }) {
103
  </span>
104
 
105
  <div className="lecturer-metric-copy">
106
- <p>{metric.label}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  <div className="lecturer-metric-value-row">
108
  <strong>{metric.value}</strong>
109
  {metric.description && (
@@ -145,7 +166,13 @@ export default function Dosen() {
145
  }),
146
  );
147
 
148
- setKnowledgeBases(rows);
 
 
 
 
 
 
149
  })
150
  .catch((e: Error) => setStatusMessage(e.message))
151
  .finally(() => setIsLoading(false));
@@ -166,6 +193,7 @@ export default function Dosen() {
166
  icon: Database,
167
  label: 'Total Knowledge Base',
168
  tone: 'primary',
 
169
  value: String(knowledgeBases.length),
170
  },
171
  {
@@ -173,6 +201,7 @@ export default function Dosen() {
173
  label: 'Total Dokumen',
174
  description: 'Chunked',
175
  tone: 'primary',
 
176
  value: String(documentCount),
177
  },
178
  {
@@ -180,6 +209,7 @@ export default function Dosen() {
180
  label: 'Processing Error',
181
  description: 'dokumen',
182
  tone: 'danger',
 
183
  value: String(failedDocumentCount),
184
  },
185
  ];
 
1
  import { Head, router } from '@inertiajs/react';
2
  import type { LucideIcon } from 'lucide-react';
3
+ import { AlertTriangle, Database, FileText, Info, Plus, Search } from 'lucide-react';
4
  import type { FormEvent, ReactNode } from 'react';
5
  import { useEffect, useMemo, useState } from 'react';
6
 
 
19
  import { Input } from '@/components/ui/input';
20
  import { Label } from '@/components/ui/label';
21
  import { LoadingIndicator } from '@/components/ui/loading-indicator';
22
+ import {
23
+ Tooltip,
24
+ TooltipContent,
25
+ TooltipProvider,
26
+ TooltipTrigger,
27
+ } from '@/components/ui/tooltip';
28
  import {
29
  createCourse,
30
  listCourseDocuments,
 
47
  label: string;
48
  value: ReactNode;
49
  description?: string;
50
+ tooltip?: string;
51
  icon: LucideIcon;
52
  tone: 'primary' | 'danger';
53
  };
 
110
  </span>
111
 
112
  <div className="lecturer-metric-copy">
113
+ <div className="flex items-center gap-1.5">
114
+ <p>{metric.label}</p>
115
+ {metric.tooltip && (
116
+ <TooltipProvider>
117
+ <Tooltip>
118
+ <TooltipTrigger asChild>
119
+ <Info className="size-3.5 cursor-help text-muted-foreground" />
120
+ </TooltipTrigger>
121
+ <TooltipContent side="top">
122
+ {metric.tooltip}
123
+ </TooltipContent>
124
+ </Tooltip>
125
+ </TooltipProvider>
126
+ )}
127
+ </div>
128
  <div className="lecturer-metric-value-row">
129
  <strong>{metric.value}</strong>
130
  {metric.description && (
 
166
  }),
167
  );
168
 
169
+ setKnowledgeBases(
170
+ [...rows].sort((a, b) => {
171
+ if (a.updatedAt === '-') return 1;
172
+ if (b.updatedAt === '-') return -1;
173
+ return b.updatedAt.localeCompare(a.updatedAt);
174
+ }),
175
+ );
176
  })
177
  .catch((e: Error) => setStatusMessage(e.message))
178
  .finally(() => setIsLoading(false));
 
193
  icon: Database,
194
  label: 'Total Knowledge Base',
195
  tone: 'primary',
196
+ tooltip: 'Jumlah mata kuliah / topik yang sudah Anda buat sebagai sumber pengetahuan AI.',
197
  value: String(knowledgeBases.length),
198
  },
199
  {
 
201
  label: 'Total Dokumen',
202
  description: 'Chunked',
203
  tone: 'primary',
204
+ tooltip: 'Jumlah dokumen yang sudah berhasil diproses dan dipotong-potong (chunked) oleh sistem agar bisa dibaca AI.',
205
  value: String(documentCount),
206
  },
207
  {
 
209
  label: 'Processing Error',
210
  description: 'dokumen',
211
  tone: 'danger',
212
+ tooltip: 'Jumlah dokumen yang gagal diproses. Dokumen ini tidak akan bisa digunakan AI untuk menjawab pertanyaan.',
213
  value: String(failedDocumentCount),
214
  },
215
  ];
resources/js/pages/mahasiswa-chat.tsx CHANGED
@@ -1117,7 +1117,7 @@ export default function MahasiswaChat({ sessionId }: MahasiswaChatProps) {
1117
  </span>
1118
  <div className="student-message-bubble student-message-bubble--typing">
1119
  <LoadingIndicator
1120
- label="Thinking"
1121
  showSpinner={false}
1122
  />
1123
  </div>
 
1117
  </span>
1118
  <div className="student-message-bubble student-message-bubble--typing">
1119
  <LoadingIndicator
1120
+ label="RAG Hub sedang berpikir"
1121
  showSpinner={false}
1122
  />
1123
  </div>
resources/js/pages/mahasiswa.tsx CHANGED
@@ -129,13 +129,13 @@ export default function Mahasiswa() {
129
  <div className="student-greeting">
130
  <h2>
131
  {isProcessing
132
- ? 'The Assistant is thinking...'
133
  : `Good Morning, ${studentName}`}
134
  </h2>
135
  {isProcessing ? (
136
  <p>
137
  <LoadingIndicator
138
- label="Bot sedang memikirkan jawaban"
139
  showSpinner={false}
140
  />
141
  </p>
 
129
  <div className="student-greeting">
130
  <h2>
131
  {isProcessing
132
+ ? 'RAG Hub sedang berpikir...'
133
  : `Good Morning, ${studentName}`}
134
  </h2>
135
  {isProcessing ? (
136
  <p>
137
  <LoadingIndicator
138
+ label="RAG Hub sedang memikirkan jawaban"
139
  showSpinner={false}
140
  />
141
  </p>