refactor: migrate from supabase to pocketbase and improve dashboard UI

This commit is contained in:
NalagamdinniRaju 2026-02-26 11:48:44 +05:30
parent 15a7cf3ac4
commit 979516b681

View File

@ -2,7 +2,8 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import QRCode from 'qrcode'; import QRCode from 'qrcode';
import { supabase } from '~/lib/supabase'; import { pb } from '~/lib/pocketbase';
import { ImageOff } from 'lucide-react';
export default function Dashboard() { export default function Dashboard() {
const [name, setName] = useState(''); const [name, setName] = useState('');
@ -12,12 +13,15 @@ export default function Dashboard() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const fetchAssets = async () => { const fetchAssets = async () => {
const { data } = await supabase try {
.from('ar_assets') const records = await pb.collection('ar_assets').getFullList({
.select('*') sort: '-created',
.order('created_at', { ascending: false }); });
setAssets(records);
setAssets(data || []); } catch (err) {
console.error('Failed to fetch assets:', err);
setAssets([]);
}
}; };
useEffect(() => { useEffect(() => {
@ -25,31 +29,21 @@ export default function Dashboard() {
}, []); }, []);
const createAsset = async () => { const createAsset = async () => {
if (!name || !glbUrl || !usdzUrl) { if (!name || !glbUrl) {
alert('Fill all fields'); alert('Please provide a name and a GLB URL');
return; return;
} }
setLoading(true); setLoading(true);
const { data, error } = await supabase try {
.from('ar_assets') const record = await pb.collection('ar_assets').create({
.insert({
name, name,
glb_url: glbUrl, glb_url: glbUrl,
usdz_url: usdzUrl, usdz_url: usdzUrl || '',
}) });
.select()
.single();
if (error || !data) { const qrUrl = `${import.meta.env.VITE_FRONTEND_URL}/ar/${record.id}`;
alert(error?.message);
setLoading(false);
return;
}
// const qrUrl = `http://10.20.2.107:5173/ar/${data.id}`;
const qrUrl = `${window.location.origin}/ar/${data.id}`;
const qrImage = await QRCode.toDataURL(qrUrl, { const qrImage = await QRCode.toDataURL(qrUrl, {
width: 512, width: 512,
@ -57,30 +51,23 @@ export default function Dashboard() {
}); });
const qrBlob = await (await fetch(qrImage)).blob(); const qrBlob = await (await fetch(qrImage)).blob();
const filePath = `${data.id}.png`;
await supabase.storage.from('qr-codes').upload(filePath, qrBlob, { const qrFormData = new FormData();
upsert: true, qrFormData.append('qr_url', qrUrl);
contentType: 'image/png', qrFormData.append('qr_image', new File([qrBlob], `${record.id}.png`, { type: 'image/png' }));
});
const { data: publicUrl } = supabase.storage await pb.collection('ar_assets').update(record.id, qrFormData);
.from('qr-codes')
.getPublicUrl(filePath);
await supabase
.from('ar_assets')
.update({
qr_url: qrUrl,
qr_image_url: publicUrl.publicUrl,
})
.eq('id', data.id);
setName(''); setName('');
setGlbUrl(''); setGlbUrl('');
setUsdzUrl(''); setUsdzUrl('');
setLoading(false);
fetchAssets(); fetchAssets();
} catch (err: any) {
alert(err?.message || 'Failed to create asset');
} finally {
setLoading(false);
}
}; };
return ( return (
@ -101,25 +88,36 @@ export default function Dashboard() {
</h2> </h2>
<div className='grid gap-4 md:grid-cols-3 text-black'> <div className='grid gap-4 md:grid-cols-3 text-black'>
<div className="space-y-1">
<label className="text-xs font-semibold text-gray-600 ml-1">Asset Name</label>
<input <input
className='rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-black focus:outline-none' className='w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-black focus:outline-none'
placeholder='Asset name' placeholder='Asset name'
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
/> />
</div>
<div className="space-y-1">
<label className="text-xs font-semibold text-gray-600 ml-1">GLB URL (Android/Web)</label>
<input <input
className='rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-black focus:outline-none' type="url"
placeholder='GLB URL' className='w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-black focus:outline-none'
placeholder='https://example.com/model.glb'
value={glbUrl} value={glbUrl}
onChange={(e) => setGlbUrl(e.target.value)} onChange={(e) => setGlbUrl(e.target.value)}
/> />
</div>
<div className="space-y-1">
<label className="text-xs font-semibold text-gray-600 ml-1">USDZ URL (iOS) - Optional</label>
<input <input
className='rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-black focus:outline-none' type="url"
className='w-full rounded-lg border border-gray-300 px-4 py-2 text-sm focus:border-black focus:outline-none'
placeholder='USDZ URL' placeholder='USDZ URL'
value={usdzUrl} value={usdzUrl}
onChange={(e) => setUsdzUrl(e.target.value)} onChange={(e) => setUsdzUrl(e.target.value)}
/> />
</div> </div>
</div>
<button <button
onClick={createAsset} onClick={createAsset}
@ -150,15 +148,16 @@ export default function Dashboard() {
{asset?.name} {asset?.name}
</h3> </h3>
{asset?.qr_image_url ? ( {asset?.qr_image ? (
<img <img
src={asset?.qr_image_url} src={pb.files.getURL(asset, asset.qr_image)}
alt={asset?.name} alt={asset?.name}
className='mx-auto w-40 rounded-lg' className='mx-auto w-40 rounded-lg'
/> />
) : ( ) : (
<div className='flex h-40 items-center justify-center rounded-lg bg-gray-100 text-sm text-gray-400'> <div className='mx-auto flex h-40 w-40 flex-col items-center justify-center space-y-2 rounded-lg bg-gray-50 text-gray-400'>
No QR <ImageOff size={32} strokeWidth={1.5} />
<span className='text-xs font-medium'>No QR Image</span>
</div> </div>
)} )}
</div> </div>
@ -170,3 +169,4 @@ export default function Dashboard() {
</div> </div>
); );
} }