fix: Auth URL race, Seeder Reset 500, and UI confirmation modal
- auth.ts: await initConfig() before refreshSession to fix localhost fallback - server.js: optional chaining req.body?.password for reset endpoint - seeder/page.tsx: replace confirm() with elegant AlertDialog for reset
This commit is contained in:
parent
621e4594c6
commit
5155fa853d
7 changed files with 55 additions and 10 deletions
BIN
frontend-source.tar.gz
Normal file
BIN
frontend-source.tar.gz
Normal file
Binary file not shown.
|
|
@ -27,6 +27,8 @@ export default function SeederPage() {
|
|||
const [processStatus, setProcessStatus] = useState<'idle' | 'running' | 'success' | 'error'>('idle');
|
||||
const scrollEndRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
||||
|
||||
// Auto-scroll to bottom of logs
|
||||
useEffect(() => {
|
||||
if (scrollEndRef.current) {
|
||||
|
|
@ -54,7 +56,11 @@ export default function SeederPage() {
|
|||
if (type === 'reset') {
|
||||
// Legacy Reset (POST) - Mimic stream output
|
||||
setLogs(['🚀 Starting flush/reset process...']);
|
||||
const res = await fetch(`${getSeederApiUrl()}/reset`, { method: 'POST' });
|
||||
const res = await fetch(`${getSeederApiUrl()}/reset`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }, // Fix for Express parsing empty body if needed
|
||||
body: JSON.stringify({}) // Explicit empty body
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
setLogs(prev => [...prev, '✅ Reset completed successfully!', JSON.stringify(data, null, 2)]);
|
||||
|
|
@ -196,9 +202,7 @@ export default function SeederPage() {
|
|||
</ul>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (confirm("Tem certeza ABSOLUTA?")) handleStream('reset', 'reset');
|
||||
}}
|
||||
onClick={() => setShowConfirmDialog(true)}
|
||||
disabled={isSeeding || isResetting}
|
||||
className="w-full"
|
||||
variant="destructive"
|
||||
|
|
@ -277,6 +281,37 @@ export default function SeederPage() {
|
|||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Confirmation Dialog */}
|
||||
<Dialog open={showConfirmDialog} onOpenChange={setShowConfirmDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2 text-destructive">
|
||||
<AlertTriangle className="h-6 w-6" />
|
||||
Atenção Absoluta!
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-base pt-2">
|
||||
Você está prestes a <strong>APAGAR TODOS OS DADOS</strong> do banco de dados (exceto admin).
|
||||
<br /><br />
|
||||
Esta ação é irreversível. Todas as vagas, candidaturas e empresas serão perdidas.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter className="gap-2 sm:gap-0">
|
||||
<Button variant="ghost" onClick={() => setShowConfirmDialog(false)}>
|
||||
Cancelar, me tire daqui!
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
setShowConfirmDialog(false);
|
||||
handleStream('reset', 'reset');
|
||||
}}
|
||||
>
|
||||
Sim, apagar tudo
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"backoffice": "Backoffice",
|
||||
"messages": "Messages",
|
||||
"tickets": "Tickets",
|
||||
"settings": "Settings",
|
||||
"my_jobs": "My Jobs",
|
||||
"applications": "Applications",
|
||||
"my_applications": "My Applications",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"backoffice": "Backoffice",
|
||||
"messages": "Mensagens",
|
||||
"tickets": "Tickets",
|
||||
"settings": "Configurações",
|
||||
"my_jobs": "Minhas Vagas",
|
||||
"applications": "Candidaturas",
|
||||
"my_applications": "Minhas Candidaturas",
|
||||
|
|
|
|||
|
|
@ -122,6 +122,11 @@ function mapRoleFromBackend(roles: string[]): "candidate" | "admin" | "company"
|
|||
*/
|
||||
export async function refreshSession(): Promise<User | null> {
|
||||
try {
|
||||
// Ensure runtime config is loaded before making the request
|
||||
if (typeof window !== "undefined") {
|
||||
await import("./config").then((m) => m.initConfig());
|
||||
}
|
||||
|
||||
console.log("%c[AUTH] Attempting to refresh session...", "color: #3b82f6");
|
||||
const res = await fetch(`${getApiV1Url()}/users/me`, {
|
||||
method: "GET",
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ async function seedDatabase() {
|
|||
// Lite version (skips cities for faster seeding)
|
||||
async function seedDatabaseLite() {
|
||||
console.log('🌱 Starting database seeding (LITE - no cities)...\n');
|
||||
console.log('🔍 Debug: seedDatabaseLite started');
|
||||
console.log('🌶️ PASSWORD_PEPPER:', process.env.PASSWORD_PEPPER ? `"${process.env.PASSWORD_PEPPER}"` : '(not set)');
|
||||
|
||||
try {
|
||||
|
|
@ -138,9 +139,13 @@ async function seedDatabaseLite() {
|
|||
console.log('');
|
||||
|
||||
// Seed in order (respecting foreign key dependencies)
|
||||
console.log('🔍 Debug: seeding location data (lite)...');
|
||||
await seedLocationDataLite(); // ⚡ Fast mode - no cities
|
||||
console.log('🔍 Debug: seeding companies...');
|
||||
await seedCompanies();
|
||||
console.log('🔍 Debug: seeding users...');
|
||||
await seedUsers();
|
||||
console.log('🔍 Debug: seeding jobs...');
|
||||
await seedJobs();
|
||||
await seedAcmeCorp();
|
||||
await seedWileECoyote();
|
||||
|
|
@ -152,13 +157,13 @@ async function seedDatabaseLite() {
|
|||
await seedTags();
|
||||
|
||||
console.log('\n✅ Database seeding (LITE) completed successfully!');
|
||||
console.log('🔍 Debug: seedDatabaseLite finished normally');
|
||||
console.log(' ⚡ Cities skipped for faster seeding');
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ Seeding failed:', error.message);
|
||||
console.error(error);
|
||||
} finally {
|
||||
await closePool();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,8 +199,7 @@ async function seedDatabaseNoLocations() {
|
|||
} catch (error) {
|
||||
console.error('\n❌ Seeding failed:', error.message);
|
||||
console.error(error);
|
||||
} finally {
|
||||
await closePool();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -233,4 +237,3 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|||
}
|
||||
})();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ app.post('/reset', async (req, res) => {
|
|||
return res.status(409).json({ error: 'Seeding/Reset in progress' });
|
||||
}
|
||||
|
||||
const password = req.body.password;
|
||||
const password = req.body?.password;
|
||||
if (process.env.SEED_PASSWORD && password !== process.env.SEED_PASSWORD) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue