chore: make seed idempotent and fix reset suspense

This commit is contained in:
Tero Halla-aho 2025-11-24 20:22:52 +02:00
parent fb1489e8f0
commit 91abec0295
2 changed files with 121 additions and 113 deletions

View file

@ -1,10 +1,10 @@
'use client';
import { useEffect, useState } from 'react';
import { Suspense, useEffect, useState } from 'react';
import { useSearchParams } from 'next/navigation';
import { useI18n } from '../../components/I18nProvider';
export default function ResetPasswordPage() {
function ResetForm() {
const { t } = useI18n();
const searchParams = useSearchParams();
const [password, setPassword] = useState('');
@ -66,3 +66,11 @@ export default function ResetPasswordPage() {
</main>
);
}
export default function ResetPasswordPage() {
return (
<Suspense fallback={<main className="panel" style={{ maxWidth: 480, margin: '40px auto' }}><p>Loading</p></main>}>
<ResetForm />
</Suspense>
);
}

View file

@ -55,12 +55,6 @@ async function main() {
}
const sampleHostHash = await bcrypt.hash('changeme-sample', 12);
const existing = await prisma.listingTranslation.findFirst({ where: { slug: SAMPLE_SLUG } });
if (existing) {
console.log('Sample listing already exists, skipping seed.');
return;
}
const owner = await prisma.user.upsert({
where: { email: SAMPLE_EMAIL },
update: {
@ -84,15 +78,12 @@ async function main() {
},
});
const listing = await prisma.listing.create({
data: {
ownerId: owner.id,
status: ListingStatus.PUBLISHED,
approvedAt: new Date(),
approvedById: adminUser ? adminUser.id : owner.id,
country: 'Finland',
region: 'South Karelia',
const listings = [
{
slug: SAMPLE_SLUG,
city: 'Punkaharju',
region: 'South Karelia',
country: 'Finland',
streetAddress: 'Saimaan rantatie 12',
addressNote: 'Lakeside trail, 5 min from main road',
latitude: 61.756,
@ -104,65 +95,28 @@ async function main() {
hasSauna: true,
hasFireplace: true,
hasWifi: true,
hasAirConditioning: false,
petsAllowed: false,
byTheLake: true,
hasAirConditioning: false,
evCharging: 'FREE',
priceHintPerNightCents: 14500,
contactName: 'Sample Host',
contactEmail: SAMPLE_EMAIL,
contactPhone: '+358401234567',
externalUrl: 'https://example.com/saimaa-cabin',
published: true,
images: {
createMany: {
data: [
{
cover: {
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
altText: 'Lakeside cabin with sauna',
isCover: true,
order: 1,
},
{
url: 'https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?auto=format&fit=crop&w=1600&q=80',
altText: 'Wood-fired sauna by the lake',
order: 2,
},
{
url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80',
altText: 'Living area with fireplace',
order: 3,
},
images: [
{ url: 'https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?auto=format&fit=crop&w=1600&q=80', altText: 'Wood-fired sauna by the lake' },
{ url: 'https://images.unsplash.com/photo-1470246973918-29a93221c455?auto=format&fit=crop&w=1600&q=80', altText: 'Living area with fireplace' },
],
},
},
},
});
await prisma.listingTranslation.createMany({
data: [
{
listingId: listing.id,
locale: DEFAULT_LOCALE,
slug: SAMPLE_SLUG,
title: 'Saimaa lakeside cabin with sauna',
description:
titleEn: 'Saimaa lakeside cabin with sauna',
teaserEn: 'Sauna, lake view, private dock, and cozy fireplace.',
descEn:
'Classic timber cabin right on Lake Saimaa. Wood-fired sauna, private dock, and a short forest walk to the nearest village. Perfect for slow weekends and midsummer gatherings.',
teaser: 'Sauna, lake view, private dock, and cozy fireplace.',
},
{
listingId: listing.id,
locale: 'fi',
slug: SAMPLE_SLUG,
title: 'Saimaan rantamökki saunalla',
description:
titleFi: 'Saimaan rantamökki saunalla',
teaserFi: 'Puusauna, järvinäköala, oma laituri ja takka.',
descFi:
'Perinteinen hirsimökki Saimaan rannalla. Puusauna, oma laituri ja lyhyt metsäreitti kylään. Sopii täydellisesti viikonloppuihin ja juhannukseen.',
teaser: 'Puusauna, järvinäköala, oma laituri ja takka.',
},
],
});
const extraListings = [
{
slug: 'helsinki-design-loft',
city: 'Helsinki',
@ -469,7 +423,9 @@ async function main() {
},
];
for (const item of extraListings) {
for (const item of listings) {
const existing = await prisma.listingTranslation.findFirst({ where: { slug: item.slug }, select: { listingId: true } });
if (!existing) {
const created = await prisma.listing.create({
data: {
ownerId: owner.id,
@ -502,31 +458,14 @@ async function main() {
translations: {
createMany: {
data: [
{
locale: 'en',
slug: item.slug,
title: item.titleEn,
teaser: item.teaserEn,
description: item.descEn,
},
{
locale: 'fi',
slug: item.slug,
title: item.titleFi,
teaser: item.teaserFi,
description: item.descFi,
},
{ locale: 'en', slug: item.slug, title: item.titleEn, teaser: item.teaserEn, description: item.descEn },
{ locale: 'fi', slug: item.slug, title: item.titleFi, teaser: item.teaserFi, description: item.descFi },
],
},
},
images: {
create: [
{
url: item.cover.url,
altText: item.cover.altText,
order: 1,
isCover: true,
},
{ url: item.cover.url, altText: item.cover.altText, order: 1, isCover: true },
...item.images.map((img, idx) => ({
url: img.url,
altText: img.altText ?? null,
@ -538,9 +477,70 @@ async function main() {
},
});
console.log('Seeded listing:', created.id, item.slug);
continue;
}
console.log('Seeded sample listing at slug:', SAMPLE_SLUG);
const listingId = existing.listingId;
await prisma.listing.update({
where: { id: listingId },
data: {
country: item.country,
region: item.region,
city: item.city,
streetAddress: item.streetAddress,
addressNote: item.addressNote,
latitude: item.latitude,
longitude: item.longitude,
maxGuests: item.maxGuests,
bedrooms: item.bedrooms,
beds: item.beds,
bathrooms: item.bathrooms,
hasSauna: item.hasSauna,
hasFireplace: item.hasFireplace,
hasWifi: item.hasWifi,
hasAirConditioning: item.hasAirConditioning,
petsAllowed: item.petsAllowed,
byTheLake: item.byTheLake,
evCharging: item.evCharging,
priceHintPerNightCents: item.priceHintPerNightCents,
contactName: 'Sample Host',
contactEmail: SAMPLE_EMAIL,
contactPhone: owner.phone,
published: true,
status: ListingStatus.PUBLISHED,
approvedAt: new Date(),
},
});
await prisma.listingTranslation.upsert({
where: { slug_locale: { slug: item.slug, locale: 'en' } },
create: { listingId, locale: 'en', slug: item.slug, title: item.titleEn, teaser: item.teaserEn, description: item.descEn },
update: { title: item.titleEn, teaser: item.teaserEn, description: item.descEn },
});
await prisma.listingTranslation.upsert({
where: { slug_locale: { slug: item.slug, locale: 'fi' } },
create: { listingId, locale: 'fi', slug: item.slug, title: item.titleFi, teaser: item.teaserFi, description: item.descFi },
update: { title: item.titleFi, teaser: item.teaserFi, description: item.descFi },
});
await prisma.listingImage.deleteMany({ where: { listingId } });
await prisma.listingImage.createMany({
data: [
{ listingId, url: item.cover.url, altText: item.cover.altText, order: 1, isCover: true },
...item.images.map((img, idx) => ({
listingId,
url: img.url,
altText: img.altText ?? null,
order: idx + 2,
isCover: false,
})),
],
});
console.log('Updated listing:', item.slug);
}
console.log('Seed completed for sample listings.');
}
main()