Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b5839ebd5 | ||
|
|
e2742a7a60 | ||
|
|
ae22adee40 |
@@ -80,7 +80,9 @@ function renderTauriDeepLinkPage(targetUrl: string): Response {
|
|||||||
const escapedPath = pathAndQuery.replace(/"/g, '"');
|
const escapedPath = pathAndQuery.replace(/"/g, '"');
|
||||||
// intent:// scheme: Chrome on Android opens the target app by package name
|
// intent:// scheme: Chrome on Android opens the target app by package name
|
||||||
// browser_fallback_url: shown if the app isn't installed
|
// browser_fallback_url: shown if the app isn't installed
|
||||||
const intentUrl = `intent:${escapedPath}#Intent;scheme=zeavisedu;package=com.zeavis.edu;S.browser_fallback_url=${encodeURIComponent(targetUrl)};end`;
|
// Use intent://login/... to produce data URI zeavisedu://login/login?token=xxx
|
||||||
|
// which new URL() can parse (single-slash non-hierarchical URLs break WebView)
|
||||||
|
const intentUrl = `intent://login${escapedPath}#Intent;scheme=zeavisedu;package=com.zeavis.edu;S.browser_fallback_url=${encodeURIComponent(targetUrl)};end`;
|
||||||
|
|
||||||
const html = `<!DOCTYPE html>
|
const html = `<!DOCTYPE html>
|
||||||
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
|||||||
@@ -35,20 +35,25 @@ export async function setupDeepLinkHandler(): Promise<void> {
|
|||||||
const { onOpenUrl } = await import('@tauri-apps/plugin-deep-link');
|
const { onOpenUrl } = await import('@tauri-apps/plugin-deep-link');
|
||||||
onOpenUrl((urls) => {
|
onOpenUrl((urls) => {
|
||||||
for (const url of urls) {
|
for (const url of urls) {
|
||||||
// url looks like: zeavisedu://zeavisedu.asepharyana.my.id/login?token=xxx
|
// url looks like: zeavisedu://login/login?token=xxx
|
||||||
// Extract path + query after the host
|
// Extract path + query after the host
|
||||||
try {
|
try {
|
||||||
const u = new URL(url);
|
const u = new URL(url);
|
||||||
const target = u.pathname + u.search + u.hash;
|
const target = u.pathname + u.search + u.hash;
|
||||||
if (target && target !== '/') {
|
if (target && target !== '/') {
|
||||||
window.location.href = target;
|
window.location.href = target;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch { /* try fallback below */ }
|
||||||
// If URL parsing fails, try to extract everything after the scheme
|
|
||||||
const match = url.match(/^[^:]+:\/\/(?:[^/]+)?(\/.*)?$/);
|
// Fallback: extract everything after scheme, handling both // and /
|
||||||
if (match?.[1]) {
|
let match = url.match(/^[^:]+:\/\/(?:[^/]+)?(\/.*)?$/);
|
||||||
window.location.href = match[1];
|
if (!match) {
|
||||||
}
|
// Also handle single-slash non-hierarchical URLs (e.g. zeavisedu:/path)
|
||||||
|
match = url.match(/^[^:]+:\/(\/.*)?$/);
|
||||||
|
}
|
||||||
|
if (match?.[1]) {
|
||||||
|
window.location.href = match[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ export function CatalogPage() {
|
|||||||
<div className="space-y-6 max-w-5xl mx-auto pb-10">
|
<div className="space-y-6 max-w-5xl mx-auto pb-10">
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl md:text-3xl font-extrabold text-[#214B11]">
|
<h1 className="text-2xl font-bold text-emerald-800">
|
||||||
Pustaka Penyakit
|
Pustaka Penyakit
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-1 text-muted-foreground text-sm md:text-base">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Referensi lengkap penyakit dan kondisi daun jagung yang dapat
|
Referensi lengkap penyakit dan kondisi daun jagung yang dapat
|
||||||
dideteksi oleh sistem AI ZeaVis Edu.
|
dideteksi oleh sistem AI ZeaVis Edu
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export function DiagnosesPage() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-emerald-800">Diagnosa Tanaman</h1>
|
<h1 className="text-2xl font-bold text-emerald-800">Diagnosa Penyakit</h1>
|
||||||
<p className="text-gray-500 mt-1 text-md">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Lihat hasil diagnosa dari scan yang telah dilakukan
|
Lihat hasil diagnosa dari scan yang telah dilakukan
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export function ExpertReviewsPage() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-emerald-800">Review Pakar</h1>
|
<h1 className="text-2xl font-bold text-emerald-800">Tinjauan Pakar</h1>
|
||||||
<p className="text-gray-500 mt-1 text-md">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Tinjau hasil diagnosa dari scan yang telah dilakukan dan berikan
|
Tinjau hasil diagnosa dari scan yang telah dilakukan dan berikan
|
||||||
feedback untuk meningkatkan akurasi sistem AI ZeaVis Edu
|
feedback untuk meningkatkan akurasi sistem AI ZeaVis Edu
|
||||||
|
|||||||
@@ -36,21 +36,18 @@ export function ScanPage() {
|
|||||||
|
|
||||||
// Camera mode state
|
// Camera mode state
|
||||||
const [useCamera, setUseCamera] = useState(false);
|
const [useCamera, setUseCamera] = useState(false);
|
||||||
const handleCameraCapture = useCallback(
|
const handleCameraCapture = useCallback((file: File) => {
|
||||||
(file: File) => {
|
setFileName(file.name);
|
||||||
setFileName(file.name);
|
const url = URL.createObjectURL(file);
|
||||||
const url = URL.createObjectURL(file);
|
setPreviewUrl(url);
|
||||||
setPreviewUrl(url);
|
|
||||||
|
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
setImageDimensions({ width: img.width, height: img.height });
|
setImageDimensions({ width: img.width, height: img.height });
|
||||||
};
|
};
|
||||||
img.src = url;
|
img.src = url;
|
||||||
setUseCamera(false);
|
setUseCamera(false);
|
||||||
},
|
}, []);
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: (file: File) => apiClient.createDiagnosis(file),
|
mutationFn: (file: File) => apiClient.createDiagnosis(file),
|
||||||
@@ -107,10 +104,10 @@ export function ScanPage() {
|
|||||||
{/* Main Header */}
|
{/* Main Header */}
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-emerald-800">Scan Tanaman</h1>
|
<h1 className="text-2xl font-bold text-emerald-800">Pindai Daun</h1>
|
||||||
<p className="text-gray-500 mt-1 text-md">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Unggah foto daun jagung untuk dianalisis oleh sistem AI kami secara
|
Unggah foto daun jagung untuk dianalisis oleh sistem AI kami secara
|
||||||
real-time.
|
real-time
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button asChild variant="outline">
|
<Button asChild variant="outline">
|
||||||
@@ -170,12 +167,16 @@ export function ScanPage() {
|
|||||||
className="w-full border-2 border-dashed border-green-300 rounded-md p-10 h-60 text-center cursor-pointer"
|
className="w-full border-2 border-dashed border-green-300 rounded-md p-10 h-60 text-center cursor-pointer"
|
||||||
onClick={() => inputRef.current?.click()}
|
onClick={() => inputRef.current?.click()}
|
||||||
>
|
>
|
||||||
<Upload className="mx-auto text-green-500 mb-3" size={48} />
|
<Upload
|
||||||
|
className="mx-auto text-green-500 mb-3"
|
||||||
|
size={48}
|
||||||
|
/>
|
||||||
<h3 className="font-semibold text-base text-gray-800 mb-1">
|
<h3 className="font-semibold text-base text-gray-800 mb-1">
|
||||||
Seret & Lepas Foto Daun
|
Seret & Lepas Foto Daun
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-xs text-gray-500 mb-3">
|
<p className="text-xs text-gray-500 mb-3">
|
||||||
atau klik untuk memilih file berkas dari perangkat Anda
|
atau klik untuk memilih file berkas dari perangkat
|
||||||
|
Anda
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-2 justify-center">
|
<div className="flex flex-wrap gap-2 justify-center">
|
||||||
<div className="bg-green-100 text-green-700 px-3 py-1 rounded-full inline-flex items-center gap-1 text-xs font-medium">
|
<div className="bg-green-100 text-green-700 px-3 py-1 rounded-full inline-flex items-center gap-1 text-xs font-medium">
|
||||||
|
|||||||
@@ -286,12 +286,11 @@ export function TelemetryPage() {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl md:text-[28px] font-extrabold text-[#214B11] flex items-center gap-3">
|
<h1 className="text-2xl font-bold text-emerald-800">
|
||||||
<Activity className="h-7 w-7 text-[#48A111]" />
|
|
||||||
Telemetry Dashboard
|
Telemetry Dashboard
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm text-muted-foreground mt-0.5">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Real-time metrics from Prometheus
|
Real-time monitoring dari performa sistem dan aplikasi ZeaVis Edu
|
||||||
{error && <span className="text-amber-600 ml-2">(partial — {error})</span>}
|
{error && <span className="text-amber-600 ml-2">(partial — {error})</span>}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user