diff --git a/src/api.js b/src/api.js new file mode 100644 index 0000000..4d0b40d --- /dev/null +++ b/src/api.js @@ -0,0 +1,93 @@ +// src/api.js +// API utama untuk flow auth dan solid data (upload, fetch dokumen, organisasi) + +// Membuat header auth +export const authHeaders = (extra = {}) => { + const token = localStorage.getItem("token"); + const headers = { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + ...extra, + }; + return headers; +}; + +// Ambil daftar organisasi user +export const getOrganizationsFromBackend = async () => { + const token = localStorage.getItem("token"); + if (!token) throw new Error("Token tidak ditemukan. Silakan login."); + const res = await fetch("https://bot.kediritechnopark.com/webhook/soliddata/get-organization", { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + Accept: "application/json", + }, + }); + return await res.json(); +}; + +// Pilih organisasi aktif +export const pickOrganization = async (organization_id, nama_organization) => { + const token = localStorage.getItem("token"); + const chosen = { organization_id, nama_organization }; + await fetch("https://bot.kediritechnopark.com/webhook/soliddata/pick-organization", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(chosen), + }); + localStorage.setItem("selected_organization", JSON.stringify(chosen)); +}; + +// Ambil daftar tipe dokumen (jenis dokumen) +export const fetchDocumentTypes = async (organizationId) => { + const token = localStorage.getItem("token"); + const res = await fetch( + "https://bot.kediritechnopark.com/webhook/solid-data/files", + { + method: "POST", + headers: { + "Content-Type": "application/json", + ...(token ? { Authorization: `Bearer ${token}` } : {}), + }, + body: JSON.stringify({ organization_id: organizationId }), + } + ); + return await res.json(); +}; + +// Ambil entry/data per tipe dokumen +export const fetchEntries = async (dataTypeId) => { + const token = localStorage.getItem("token"); + const res = await fetch( + "https://bot.kediritechnopark.com/webhook/solid-data/files/entry", + { + method: "POST", + headers: { + "Content-Type": "application/json", + ...(token ? { Authorization: `Bearer ${token}` } : {}), + }, + body: JSON.stringify({ data_type_id: dataTypeId }), + } + ); + return await res.json(); +}; + +// Upload dokumen (gambar/file) +export const uploadDocument = async (organizationId, dataTypeId, file) => { + const token = localStorage.getItem("token"); + const formData = new FormData(); + formData.append("organization_id", organizationId); + formData.append("data_type_id", dataTypeId); + formData.append("file", file); + const res = await fetch("https://bot.kediritechnopark.com/webhook/solid-data/upload", { + method: "POST", + headers: { + ...(token ? { Authorization: `Bearer ${token}` } : {}), + }, + body: formData, + }); + return await res.json(); +}; diff --git a/src/pages/DashboardPage.js b/src/pages/DashboardPage.js index 5b518de..4ccdc00 100644 --- a/src/pages/DashboardPage.js +++ b/src/pages/DashboardPage.js @@ -1,17 +1,8 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; +import { fetchDocumentTypes } from '../api'; import { Link } from 'react-router-dom'; import AddDocumentModal from '../components/AddDocumentModal'; // Kita akan buat ini -// Data dummy -const documentTypes = [ - { name: 'Akta Kelahiran', count: 0 }, - { name: 'Ijazah', count: 0 }, - { name: 'KK', count: 0 }, - { name: 'KTP', count: 6 }, - { name: 'Polinema', count: 3 }, - { name: 'Sampul Buku', count: 1 }, -]; - const StatCard = ({ title, value }) => (

{title}

@@ -19,17 +10,40 @@ const StatCard = ({ title, value }) => (
); -export default function DashboardPage() { +function DashboardPage() { const [isModalOpen, setIsModalOpen] = useState(false); + const [documentTypes, setDocumentTypes] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + + useEffect(() => { + const org = localStorage.getItem('selected_organization'); + if (!org) { + setError('Organisasi belum dipilih.'); + setLoading(false); + return; + } + const { organization_id } = JSON.parse(org); + setLoading(true); + fetchDocumentTypes(organization_id) + .then((data) => { + setDocumentTypes(Array.isArray(data) ? data : data.data || []); + setError(''); + }) + .catch((err) => { + setError(err.message || 'Gagal memuat dokumen'); + }) + .finally(() => setLoading(false)); + }, []); return (
{/* Statistik */}
- - - + + +
{/* Daftar Jenis Dokumen */} @@ -44,16 +58,32 @@ export default function DashboardPage() {
- {documentTypes.map((doc, index) => ( - -
{index + 1}
-
-

{doc.name}

-

{doc.count} data tersedia

-
- {/* Arrow Icon */} - - ))} + {loading ? ( +
Memuat data...
+ ) : error ? ( +
{error}
+ ) : documentTypes.length === 0 ? ( +
Belum ada jenis dokumen.
+ ) : ( + documentTypes.map((doc, index) => ( + +
{index + 1}
+
+

{doc.nama_tipe || doc.name}

+

{doc.total_entries || doc.count || 0} data tersedia

+
+ + )) + )}
@@ -61,4 +91,6 @@ export default function DashboardPage() { setIsModalOpen(false)} /> ); -} \ No newline at end of file +} + +export default DashboardPage; \ No newline at end of file diff --git a/src/pages/InputDataPage.js b/src/pages/InputDataPage.js index ba4288c..3f6b125 100644 --- a/src/pages/InputDataPage.js +++ b/src/pages/InputDataPage.js @@ -1,5 +1,5 @@ import { useState, useRef } from 'react'; -import { useParams, Link } from 'react-router-dom'; +import { useParams, Link, useLocation } from 'react-router-dom'; // Ikon (tidak ada perubahan) const BackIcon = () => (); @@ -10,6 +10,9 @@ const TrashIcon = () => ( ( @@ -7,6 +7,25 @@ const DocumentIcon = () => ( ); export default function LoginPage() { + const navigate = useNavigate(); + + const handleLogin = () => { + const baseUrl = "https://kediritechnopark.com/"; + const modal = "product"; + const productId = 9; + + // Ganti authorizedUri sesuai domain produksi Anda jika sudah deploy + const authorizedUri = window.location.origin + "/select-organization?token="; + const unauthorizedUri = `${baseUrl}?modal=${modal}&product_id=${productId}`; + + const url = + `${baseUrl}?modal=${modal}&product_id=${productId}` + + `&authorized_uri=${encodeURIComponent(authorizedUri)}` + + `&unauthorized_uri=${encodeURIComponent(unauthorizedUri)}`; + + window.location.href = url; + }; + return (
@@ -17,12 +36,12 @@ export default function LoginPage() {

SOLID DATA

Kelola data dokumen Anda dengan mudah

- Masuk - +
); diff --git a/src/pages/OrganizationPage.js b/src/pages/OrganizationPage.js index 51fa27e..a794b42 100644 --- a/src/pages/OrganizationPage.js +++ b/src/pages/OrganizationPage.js @@ -1,4 +1,6 @@ -import { Link } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; +import { getOrganizationsFromBackend, pickOrganization } from '../api'; const OrgIcon = () => ( @@ -8,37 +10,82 @@ const ArrowIcon = () => ( ); -const organizations = [ - { name: 'psi', id: 'BLWR-XDU-QRUV' }, - { name: 'managemen', id: 'NFTJ-POX-ZYOB' }, - { name: 'solid', id: 'TCKQ-ZNF-UFTW' }, -]; +function OrganizationPage() { + const [organizations, setOrganizations] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + const navigate = useNavigate(); + const location = useLocation(); + + // Simpan token dari URL ke localStorage jika ada + useEffect(() => { + const params = new URLSearchParams(location.search); + const token = params.get("token"); + if (token) { + localStorage.setItem("token", token); + // Hapus token dari URL agar tidak dikirim ulang saat reload + navigate("/select-organization", { replace: true }); + } + // eslint-disable-next-line + }, []); + + useEffect(() => { + const token = localStorage.getItem("token"); + if (!token) { + navigate("/login", { replace: true }); + return; + } + setLoading(true); + getOrganizationsFromBackend() + .then((data) => { + setOrganizations(data); + setError(''); + }) + .catch((err) => { + setError(err.message || 'Gagal memuat organisasi'); + }) + .finally(() => setLoading(false)); + }, [navigate]); + + const handleSelect = async (org) => { + await pickOrganization(org.organization_id, org.nama_organization); + navigate('/dashboard'); + }; -export default function OrganizationPage() { return (

Pilih Organisasi

Silakan pilih organisasi yang ingin Anda kelola.

-
- {organizations.map((org) => ( - -
-
-
-

{org.name}

-

ID: {org.id}

+ {loading ? ( +
Memuat organisasi...
+ ) : error ? ( +
{error}
+ ) : organizations.length === 0 ? ( +
Tidak ada organisasi untuk akun ini.
+ ) : ( +
+ {organizations.map((org) => ( +
- - - ))} -
+ + + ))} +
+ )}
); -} \ No newline at end of file +} + +export default OrganizationPage; \ No newline at end of file