chore: make seed idempotent and fix reset suspense
This commit is contained in:
parent
fb1489e8f0
commit
91abec0295
2 changed files with 121 additions and 113 deletions
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
222
prisma/seed.js
222
prisma/seed.js
|
|
@ -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: [
|
||||
{
|
||||
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,
|
||||
},
|
||||
],
|
||||
},
|
||||
cover: {
|
||||
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
|
||||
altText: 'Lakeside cabin with sauna',
|
||||
},
|
||||
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' },
|
||||
],
|
||||
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.',
|
||||
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.',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.listingTranslation.createMany({
|
||||
data: [
|
||||
{
|
||||
listingId: listing.id,
|
||||
locale: DEFAULT_LOCALE,
|
||||
slug: SAMPLE_SLUG,
|
||||
title: 'Saimaa lakeside cabin with sauna',
|
||||
description:
|
||||
'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:
|
||||
'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,13 +423,67 @@ async function main() {
|
|||
},
|
||||
];
|
||||
|
||||
for (const item of extraListings) {
|
||||
const created = await prisma.listing.create({
|
||||
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,
|
||||
status: ListingStatus.PUBLISHED,
|
||||
approvedAt: new Date(),
|
||||
approvedById: adminUser ? adminUser.id : owner.id,
|
||||
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,
|
||||
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 },
|
||||
],
|
||||
},
|
||||
},
|
||||
images: {
|
||||
create: [
|
||||
{ url: item.cover.url, altText: item.cover.altText, order: 1, isCover: true },
|
||||
...item.images.map((img, idx) => ({
|
||||
url: img.url,
|
||||
altText: img.altText ?? null,
|
||||
order: idx + 2,
|
||||
isCover: false,
|
||||
})),
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log('Seeded listing:', created.id, item.slug);
|
||||
continue;
|
||||
}
|
||||
|
||||
const listingId = existing.listingId;
|
||||
await prisma.listing.update({
|
||||
where: { id: listingId },
|
||||
data: {
|
||||
ownerId: owner.id,
|
||||
status: ListingStatus.PUBLISHED,
|
||||
approvedAt: new Date(),
|
||||
approvedById: adminUser ? adminUser.id : owner.id,
|
||||
country: item.country,
|
||||
region: item.region,
|
||||
city: item.city,
|
||||
|
|
@ -499,48 +507,40 @@ async function main() {
|
|||
contactEmail: SAMPLE_EMAIL,
|
||||
contactPhone: owner.phone,
|
||||
published: true,
|
||||
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,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
images: {
|
||||
create: [
|
||||
{
|
||||
url: item.cover.url,
|
||||
altText: item.cover.altText,
|
||||
order: 1,
|
||||
isCover: true,
|
||||
},
|
||||
...item.images.map((img, idx) => ({
|
||||
url: img.url,
|
||||
altText: img.altText ?? null,
|
||||
order: idx + 2,
|
||||
isCover: false,
|
||||
})),
|
||||
],
|
||||
},
|
||||
status: ListingStatus.PUBLISHED,
|
||||
approvedAt: new Date(),
|
||||
},
|
||||
});
|
||||
console.log('Seeded listing:', created.id, item.slug);
|
||||
|
||||
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('Seeded sample listing at slug:', SAMPLE_SLUG);
|
||||
console.log('Seed completed for sample listings.');
|
||||
}
|
||||
|
||||
main()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue