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';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { Suspense, useEffect, useState } from 'react';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import { useI18n } from '../../components/I18nProvider';
|
import { useI18n } from '../../components/I18nProvider';
|
||||||
|
|
||||||
export default function ResetPasswordPage() {
|
function ResetForm() {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
|
|
@ -66,3 +66,11 @@ export default function ResetPasswordPage() {
|
||||||
</main>
|
</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 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({
|
const owner = await prisma.user.upsert({
|
||||||
where: { email: SAMPLE_EMAIL },
|
where: { email: SAMPLE_EMAIL },
|
||||||
update: {
|
update: {
|
||||||
|
|
@ -84,15 +78,12 @@ async function main() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const listing = await prisma.listing.create({
|
const listings = [
|
||||||
data: {
|
{
|
||||||
ownerId: owner.id,
|
slug: SAMPLE_SLUG,
|
||||||
status: ListingStatus.PUBLISHED,
|
|
||||||
approvedAt: new Date(),
|
|
||||||
approvedById: adminUser ? adminUser.id : owner.id,
|
|
||||||
country: 'Finland',
|
|
||||||
region: 'South Karelia',
|
|
||||||
city: 'Punkaharju',
|
city: 'Punkaharju',
|
||||||
|
region: 'South Karelia',
|
||||||
|
country: 'Finland',
|
||||||
streetAddress: 'Saimaan rantatie 12',
|
streetAddress: 'Saimaan rantatie 12',
|
||||||
addressNote: 'Lakeside trail, 5 min from main road',
|
addressNote: 'Lakeside trail, 5 min from main road',
|
||||||
latitude: 61.756,
|
latitude: 61.756,
|
||||||
|
|
@ -104,65 +95,28 @@ async function main() {
|
||||||
hasSauna: true,
|
hasSauna: true,
|
||||||
hasFireplace: true,
|
hasFireplace: true,
|
||||||
hasWifi: true,
|
hasWifi: true,
|
||||||
|
hasAirConditioning: false,
|
||||||
petsAllowed: false,
|
petsAllowed: false,
|
||||||
byTheLake: true,
|
byTheLake: true,
|
||||||
hasAirConditioning: false,
|
|
||||||
evCharging: 'FREE',
|
evCharging: 'FREE',
|
||||||
priceHintPerNightCents: 14500,
|
priceHintPerNightCents: 14500,
|
||||||
contactName: 'Sample Host',
|
cover: {
|
||||||
contactEmail: SAMPLE_EMAIL,
|
url: 'https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=1600&q=80',
|
||||||
contactPhone: '+358401234567',
|
altText: 'Lakeside cabin with sauna',
|
||||||
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,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
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',
|
slug: 'helsinki-design-loft',
|
||||||
city: 'Helsinki',
|
city: 'Helsinki',
|
||||||
|
|
@ -469,13 +423,67 @@ async function main() {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const item of extraListings) {
|
for (const item of listings) {
|
||||||
const created = await prisma.listing.create({
|
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: {
|
data: {
|
||||||
ownerId: owner.id,
|
|
||||||
status: ListingStatus.PUBLISHED,
|
|
||||||
approvedAt: new Date(),
|
|
||||||
approvedById: adminUser ? adminUser.id : owner.id,
|
|
||||||
country: item.country,
|
country: item.country,
|
||||||
region: item.region,
|
region: item.region,
|
||||||
city: item.city,
|
city: item.city,
|
||||||
|
|
@ -499,48 +507,40 @@ async function main() {
|
||||||
contactEmail: SAMPLE_EMAIL,
|
contactEmail: SAMPLE_EMAIL,
|
||||||
contactPhone: owner.phone,
|
contactPhone: owner.phone,
|
||||||
published: true,
|
published: true,
|
||||||
translations: {
|
status: ListingStatus.PUBLISHED,
|
||||||
createMany: {
|
approvedAt: new Date(),
|
||||||
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);
|
|
||||||
|
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()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue