Initial commit

This commit is contained in:
Monarch055
2026-06-10 19:36:52 +07:00
commit 7ad037bf0a
69 changed files with 16579 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
const fs = require('fs');
let code = fs.readFileSync('src/components/Dashboard.js', 'utf8');
const imports = `import SidebarControls from './dashboard/SidebarControls';
import StatsPanel from './dashboard/StatsPanel';
import ApprovalQueueModal from './dashboard/modals/ApprovalQueueModal';
import UserProvisioningModal from './dashboard/modals/UserProvisioningModal';
import DonationModal from './dashboard/modals/DonationModal';
import HubFormModal from './dashboard/modals/HubFormModal';
import HouseholdFormModal from './dashboard/modals/HouseholdFormModal';
`;
code = code.replace("import { useRouter } from 'next/navigation';", "import { useRouter } from 'next/navigation';\n" + imports);
const leftPanelStart = code.indexOf('{/* Left Panel (Controls) */}');
const leftPanelEnd = code.indexOf('{/* Right Panel (Stats) */}');
if (leftPanelStart > -1 && leftPanelEnd > -1) {
const newLeftPanel = `{/* Left Panel (Controls) */}
<div className={\`left-panel glass-panel \${showControls ? '' : 'hidden'}\`} id="controlsPanel">
<div className="panel-title">
<span className="title-text"><i className="fas fa-sliders-h"></i> Controls</span>
<button className="btn-toggle-panel" onClick={() => setShowControls(false)} title="Hide Controls">
<i className="fas fa-chevron-left"></i>
</button>
</div>
<SidebarControls
user={user} profile={profile} router={router}
isEditMode={isEditMode} setIsEditMode={setIsEditMode}
setShowApprovalModal={setShowApprovalModal} setShowUserModal={setShowUserModal}
fetchUsers={fetchUsers} setPlacementMode={setPlacementMode}
setShowToast={setShowToast} filters={filters} setFilters={setFilters}
hubStyles={hubStyles}
/>
</div>
`;
code = code.substring(0, leftPanelStart) + newLeftPanel + code.substring(leftPanelEnd);
}
const rightPanelStart = code.indexOf('{/* Right Panel (Stats) */}');
const rightPanelEnd = code.indexOf('{/* Add Location Floating Button */}');
if (rightPanelStart > -1 && rightPanelEnd > -1) {
const newRightPanel = `{/* Right Panel (Stats) */}
<StatsPanel
profile={profile} showStats={showStats}
setShowStats={setShowStats} stats={stats}
/>
`;
code = code.substring(0, rightPanelStart) + newRightPanel + code.substring(rightPanelEnd);
}
const modalStartIndex = code.indexOf('{/* Hub Modal */}');
if (modalStartIndex > -1) {
const newModals = `
<HubFormModal
showHubModal={showHubModal} setShowHubModal={setShowHubModal}
hubFormData={hubFormData} setHubFormData={setHubFormData}
handleSaveHub={handleSaveHub} isEditMode={isEditMode}
/>
<HouseholdFormModal
showHhModal={showHhModal} setShowHhModal={setShowHhModal}
hhFormData={hhFormData} setHhFormData={setHhFormData}
handleSaveHh={handleSaveHh} hubs={hubs}
imageFile={imageFile} setImageFile={setImageFile}
isUploading={isUploading} isEditMode={isEditMode}
/>
<DonationModal
showDonationModal={showDonationModal} setShowDonationModal={setShowDonationModal}
donationFormData={donationFormData} setDonationFormData={setDonationFormData}
hubs={hubs} isSubmittingDonation={isSubmittingDonation}
handleSaveDonation={handleSaveDonation} donationsList={donationsList}
/>
<ApprovalQueueModal
showApprovalModal={showApprovalModal} setShowApprovalModal={setShowApprovalModal}
households={households} selectedPhotoUrl={selectedPhotoUrl}
setSelectedPhotoUrl={setSelectedPhotoUrl} handleVerifyAction={handleVerifyAction}
/>
<UserProvisioningModal
showUserModal={showUserModal} setShowUserModal={setShowUserModal}
usersList={usersList} profile={profile}
userFormData={userFormData} setUserFormData={setUserFormData}
handleCreateUser={handleCreateUser} isSubmittingUser={isSubmittingUser}
handleDeleteUser={handleDeleteUser}
/>
</div>
);
}`;
code = code.substring(0, modalStartIndex) + newModals;
}
fs.writeFileSync('src/components/Dashboard.js', code);
console.log('Dashboard.js successfully refactored');
+169
View File
@@ -0,0 +1,169 @@
const fs = require('fs');
let code = fs.readFileSync('src/components/Dashboard.js', 'utf8');
// 1. ADD MISSING STATE AND FUNCTIONS FOR USER PROVISIONING
const stateIndex = code.indexOf('const [isEditMode, setIsEditMode] = useState(false);');
if (stateIndex > -1) {
const userStates = `
const [showUserModal, setShowUserModal] = useState(false);
const [usersList, setUsersList] = useState([]);
const [userFormData, setUserFormData] = useState({
email: '',
password: '',
full_name: '',
role: 'pic'
});
const [isSubmittingUser, setIsSubmittingUser] = useState(false);
const fetchUsers = async () => {
try {
const res = await fetch('/api/users');
if (res.ok) {
const data = await res.json();
setUsersList(data.users || []);
}
} catch (e) { console.error('Error fetching users:', e); }
};
const handleCreateUser = async (e) => {
e.preventDefault();
setIsSubmittingUser(true);
try {
const res = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userFormData)
});
if (res.ok) {
alert('User created successfully');
fetchUsers();
setUserFormData({ email: '', password: '', full_name: '', role: 'pic' });
setShowUserModal(false);
} else {
const data = await res.json();
alert('Failed to create user: ' + data.error);
}
} catch (e) { alert('Error: ' + e.message); }
setIsSubmittingUser(false);
};
const handleDeleteUser = async (id) => {
if (!confirm('Are you sure you want to delete this user?')) return;
try {
const res = await fetch(\`/api/users?id=\${id}\`, { method: 'DELETE' });
if (res.ok) fetchUsers();
else alert('Failed to delete user');
} catch (e) { alert('Error deleting user'); }
};
`;
code = code.substring(0, stateIndex) + userStates + code.substring(stateIndex);
}
// 2. REMOVE isPointInPolygon AND getKecamatanForPoint
code = code.replace(/const isPointInPolygon = [\s\S]*?return null;\n};\n/, '');
// 3. FIX PostGIS USAGES (remove getKecamatanForPoint calls)
code = code.replace(/const calculatedKec = getKecamatanForPoint[^;]+;/g, '');
code = code.replace(/hh\.sub_district \|\| calculatedKec \|\| subDistrictsList\[idx % subDistrictsList\.length\]/g, "hh.sub_district || 'Belum Terpetakan'");
code = code.replace(/hh\.sub_district = calculatedKec \|\| hh\.sub_district \|\| subDistrictsList\[idx % subDistrictsList\.length\];/g, "hh.sub_district = hh.sub_district || 'Belum Terpetakan';");
// 4. ADD MODULAR IMPORTS
const imports = `import SidebarControls from './dashboard/SidebarControls';
import StatsPanel from './dashboard/StatsPanel';
import ApprovalQueueModal from './dashboard/modals/ApprovalQueueModal';
import UserProvisioningModal from './dashboard/modals/UserProvisioningModal';
import DonationModal from './dashboard/modals/DonationModal';
import HubFormModal from './dashboard/modals/HubFormModal';
import HouseholdFormModal from './dashboard/modals/HouseholdFormModal';
`;
code = code.replace("import { useRouter } from 'next/navigation';", "import { useRouter } from 'next/navigation';\n" + imports);
// 5. REPLACE LEFT PANEL
const leftPanelStart = code.indexOf('{/* Left Panel (Controls) */}');
const leftPanelEnd = code.indexOf('{/* Right Panel (Stats) */}');
if (leftPanelStart > -1 && leftPanelEnd > -1) {
const newLeftPanel = `{/* Left Panel (Controls) */}
<div className={\`left-panel glass-panel \${showControls ? '' : 'hidden'}\`} id="controlsPanel">
<div className="panel-title">
<span className="title-text"><i className="fas fa-sliders-h"></i> Controls</span>
<button className="btn-toggle-panel" onClick={() => setShowControls(false)} title="Hide Controls">
<i className="fas fa-chevron-left"></i>
</button>
</div>
<SidebarControls
user={user} profile={profile} router={router}
isEditMode={isEditMode} setIsEditMode={setIsEditMode}
setShowApprovalModal={setShowApprovalModal} setShowUserModal={setShowUserModal}
fetchUsers={fetchUsers} setPlacementMode={setPlacementMode}
setShowToast={setShowToast} filters={filters} setFilters={setFilters}
hubStyles={hubStyles}
/>
</div>
`;
code = code.substring(0, leftPanelStart) + newLeftPanel + code.substring(leftPanelEnd);
}
// 6. REPLACE RIGHT PANEL
const rightPanelStart = code.indexOf('{/* Right Panel (Stats) */}');
const rightPanelEnd = code.indexOf('{/* Add Location Floating Button */}');
if (rightPanelStart > -1 && rightPanelEnd > -1) {
const newRightPanel = `{/* Right Panel (Stats) */}
<StatsPanel
profile={profile} showStats={showStats}
setShowStats={setShowStats} stats={stats}
/>
`;
code = code.substring(0, rightPanelStart) + newRightPanel + code.substring(rightPanelEnd);
}
// 7. REPLACE MODALS
const modalStartIndex = code.indexOf('{/* Hub Modal */}');
if (modalStartIndex > -1) {
const newModals = `{/* Hub Modal */}
<HubFormModal
showHubModal={showHubModal} setShowHubModal={setShowHubModal}
hubFormData={hubFormData} setHubFormData={setHubFormData}
handleSaveHub={handleSaveHub} isEditMode={isEditMode}
/>
<HouseholdFormModal
showHhModal={showHhModal} setShowHhModal={setShowHhModal}
hhFormData={hhFormData} setHhFormData={setHhFormData}
handleSaveHh={handleSaveHh} hubs={hubs}
imageFile={imageFile} setImageFile={setImageFile}
isUploading={isUploading} isEditMode={isEditMode}
/>
<DonationModal
showDonationModal={showDonationModal} setShowDonationModal={setShowDonationModal}
donationFormData={donationFormData} setDonationFormData={setDonationFormData}
hubs={hubs} isSubmittingDonation={isSubmittingDonation}
handleSaveDonation={handleSaveDonation} donationsList={donationsList}
/>
<ApprovalQueueModal
showApprovalModal={showApprovalModal} setShowApprovalModal={setShowApprovalModal}
households={households} selectedPhotoUrl={selectedPhotoUrl}
setSelectedPhotoUrl={setSelectedPhotoUrl} handleVerifyAction={handleVerifyAction}
/>
<UserProvisioningModal
showUserModal={showUserModal} setShowUserModal={setShowUserModal}
usersList={usersList} profile={profile}
userFormData={userFormData} setUserFormData={setUserFormData}
handleCreateUser={handleCreateUser} isSubmittingUser={isSubmittingUser}
handleDeleteUser={handleDeleteUser}
/>
</div>
);
}`;
code = code.substring(0, modalStartIndex) + newModals;
}
fs.writeFileSync('src/components/Dashboard.js', code);
console.log('Dashboard.js completely restored and refactored!');
@@ -0,0 +1,75 @@
const fs = require('fs');
const { createClient } = require('@supabase/supabase-js');
// Parse .env.local
const envFile = fs.readFileSync('.env.local', 'utf8');
const envVars = {};
envFile.split('\n').forEach(line => {
const match = line.match(/^([^=]+)=(.*)$/);
if (match) envVars[match[1]] = match[2];
});
async function main() {
const supabaseUrl = envVars.NEXT_PUBLIC_SUPABASE_URL;
const supabaseKey = envVars.SUPABASE_SERVICE_ROLE_KEY;
if (!supabaseUrl || !supabaseKey) {
console.error('Missing Supabase credentials in .env.local');
process.exit(1);
}
const supabase = createClient(supabaseUrl, supabaseKey);
// 1. Upload Sub-districts
console.log('Reading GeoJSON...');
const geojsonRaw = fs.readFileSync('src/lib/Admin_Kecamatan.json', 'utf8');
const geojson = JSON.parse(geojsonRaw);
for (const feature of geojson.features) {
const name = feature.properties?.Ket;
if (!name) continue;
let geom = feature.geometry;
if (geom.type === 'Polygon') {
geom = {
type: 'MultiPolygon',
coordinates: [geom.coordinates]
};
}
console.log(`Uploading ${name}...`);
// Supabase auto-casts GeoJSON objects to PostGIS geometry during insert
const { error } = await supabase.from('sub_districts').upsert(
{ name: name, geom: geom },
{ onConflict: 'name' }
);
if (error) {
console.error(`Failed to upload ${name}:`, error.message);
} else {
console.log(`Success: ${name}`);
}
}
// 2. Trigger updates on existing households to populate the sub_district column
console.log('Triggering updates on existing households to populate sub_district...');
const { data: households, error: fetchErr } = await supabase.from('households').select('id, location');
if (fetchErr) {
console.error('Error fetching households:', fetchErr);
} else if (households && households.length > 0) {
console.log(`Found ${households.length} households. Updating...`);
for (const hh of households) {
// Touching the row will fire the trigger
const { error: upErr } = await supabase.from('households').update({ location: hh.location }).eq('id', hh.id);
if (upErr) console.error(`Error updating HH ${hh.id}:`, upErr.message);
}
console.log('Completed household updates.');
} else {
console.log('No households found to update.');
}
console.log('Migration complete.');
}
main();