1051 lines
41 KiB
TypeScript
1051 lines
41 KiB
TypeScript
import { db } from './db'
|
||
|
||
export interface Category {
|
||
id: string
|
||
slug: string
|
||
nameTr: string
|
||
nameEn: string
|
||
nameRu: string
|
||
}
|
||
|
||
export interface Neighborhood {
|
||
id: string
|
||
slug: string
|
||
nameTr: string
|
||
nameEn: string
|
||
nameRu: string
|
||
}
|
||
|
||
export interface Gallery {
|
||
id: string
|
||
listingId: string
|
||
url: string
|
||
}
|
||
|
||
export interface Listing {
|
||
id: string
|
||
slug: string
|
||
categoryId: string
|
||
neighborhoodId: string
|
||
city: string
|
||
nameTr: string
|
||
nameEn: string
|
||
nameRu: string
|
||
descriptionTr: string
|
||
descriptionEn: string
|
||
descriptionRu: string
|
||
address: string
|
||
phone?: string | null
|
||
whatsapp?: string | null
|
||
website?: string | null
|
||
instagram?: string | null
|
||
priceRange: number
|
||
rating?: number | null
|
||
isLocalApproved: boolean
|
||
latitude?: number | null
|
||
longitude?: number | null
|
||
openingHours?: any | null
|
||
images: Gallery[]
|
||
category?: Category
|
||
neighborhood?: Neighborhood
|
||
createdAt: Date
|
||
updatedAt: Date
|
||
deletedAt?: Date | null
|
||
|
||
// Phase 2
|
||
menuUrl?: string | null
|
||
isFeatured: boolean
|
||
featuredUntil?: Date | null
|
||
}
|
||
|
||
export interface BusinessSubmission {
|
||
id: string
|
||
businessName: string
|
||
categoryId: string
|
||
neighborhoodId: string
|
||
address: string
|
||
phone?: string | null
|
||
whatsapp?: string | null
|
||
description: string
|
||
contactName: string
|
||
contactEmail: string
|
||
imageUrl?: string | null
|
||
status: string
|
||
createdAt: Date
|
||
updatedAt: Date
|
||
}
|
||
|
||
export interface ContactMessage {
|
||
id: string
|
||
name: string
|
||
email: string
|
||
subject: string
|
||
message: string
|
||
isRead: boolean
|
||
createdAt: Date
|
||
updatedAt: Date
|
||
}
|
||
|
||
export interface BlogPost {
|
||
id: string
|
||
slug: string
|
||
titleTr: string
|
||
titleEn: string
|
||
titleRu: string
|
||
contentTr: string
|
||
contentEn: string
|
||
contentRu: string
|
||
coverImage?: string | null
|
||
tags: string[]
|
||
relatedListingIds: string[]
|
||
publishedAt?: Date | null
|
||
createdAt: Date
|
||
updatedAt: Date
|
||
deletedAt?: Date | null
|
||
}
|
||
|
||
export interface Collection {
|
||
id: string
|
||
slug: string
|
||
titleTr: string
|
||
titleEn: string
|
||
titleRu: string
|
||
descriptionTr: string
|
||
descriptionEn: string
|
||
descriptionRu: string
|
||
coverImage?: string | null
|
||
listings?: Listing[]
|
||
listingIds: string[]
|
||
createdAt: Date
|
||
updatedAt: Date
|
||
}
|
||
|
||
export interface InstagramFeedCache {
|
||
id: string
|
||
listingId: string
|
||
handle: string
|
||
posts: Array<{
|
||
imageUrl: string
|
||
caption?: string
|
||
permalink?: string
|
||
postedAt: string
|
||
}>
|
||
fetchedAt: Date
|
||
}
|
||
|
||
const globalForMockDb = globalThis as unknown as {
|
||
categories: Category[]
|
||
neighborhoods: Neighborhood[]
|
||
listings: Listing[]
|
||
submissions: BusinessSubmission[]
|
||
messages: ContactMessage[]
|
||
blogPosts: BlogPost[]
|
||
collections: Collection[]
|
||
instagramFeedCaches: InstagramFeedCache[]
|
||
initialized: boolean
|
||
}
|
||
|
||
if (!globalForMockDb.initialized) {
|
||
globalForMockDb.categories = [
|
||
{ id: 'cat-1', slug: 'restoran', nameTr: 'Restoran', nameEn: 'Restaurant', nameRu: 'Ресторан' },
|
||
{ id: 'cat-2', slug: 'apart', nameTr: 'Apart', nameEn: 'Apart Hotel', nameRu: 'Апарт-отель' },
|
||
{ id: 'cat-3', slug: 'isletme', nameTr: 'İşletme & Hizmet', nameEn: 'Business & Service', nameRu: 'Бизнес и Услуги' }
|
||
]
|
||
|
||
globalForMockDb.neighborhoods = [
|
||
{ id: 'neigh-1', slug: 'yat-limani', nameTr: 'Yat Limanı', nameEn: 'Marina', nameRu: 'Марина' },
|
||
{ id: 'neigh-2', slug: 'icmeler', nameTr: 'İçmeler', nameEn: 'Icmeler', nameRu: 'Ичмелер' },
|
||
{ id: 'neigh-3', slug: 'armutalan', nameTr: 'Armutalan', nameEn: 'Armutalan', nameRu: 'Армуталан' },
|
||
{ id: 'neigh-4', slug: 'siteler', nameTr: 'Siteler', nameEn: 'Siteler', nameRu: 'Сителер' },
|
||
{ id: 'neigh-5', slug: 'turunc', nameTr: 'Turunç', nameEn: 'Turunc', nameRu: 'Турунч' }
|
||
]
|
||
|
||
globalForMockDb.submissions = []
|
||
globalForMockDb.messages = []
|
||
|
||
// Seed Listings with Phase 2 fields
|
||
globalForMockDb.listings = [
|
||
{
|
||
id: 'list-1',
|
||
slug: 'iskele-balik-ocakbasi',
|
||
categoryId: 'cat-1',
|
||
neighborhoodId: 'neigh-1',
|
||
city: 'marmaris',
|
||
nameTr: 'İskele Balık Ocakbaşı',
|
||
nameEn: 'Iskele Fish & Grill',
|
||
nameRu: 'Рыбный Гриль Искеле',
|
||
descriptionTr: 'Yat Limanı\'nda taze Ege balıkları ve geleneksel meze çeşitleriyle yerel lezzet durağınız. Mükemmel körfez manzarası eşliğinde akşam yemeği.',
|
||
descriptionEn: 'Your local taste stop at the Marina with fresh Aegean fish and traditional appetizers. Dinner accompanied by excellent bay views.',
|
||
descriptionRu: 'Ваша местная гастрономическая остановка в Марине со свежей эгейской рыбой и традиционными закусками. Ужин в сопровождении великолепного вида на залив.',
|
||
address: 'Yat Limanı No:12, Marmaris',
|
||
phone: '+90 252 412 34 56',
|
||
whatsapp: '+90 532 123 45 67',
|
||
website: 'https://iskelemarmaris.com',
|
||
instagram: 'iskele_marmaris',
|
||
priceRange: 3,
|
||
rating: 4.8,
|
||
isLocalApproved: true,
|
||
latitude: 36.8524,
|
||
longitude: 28.2741,
|
||
openingHours: { all: '12:00 - 00:00' },
|
||
images: [
|
||
{ id: 'img-1-1', listingId: 'list-1', url: 'https://images.unsplash.com/photo-1519708227418-c8fd9a32b7a2?w=800&auto=format&fit=crop&q=80' },
|
||
{ id: 'img-1-2', listingId: 'list-1', url: 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 24 * 5),
|
||
updatedAt: new Date(),
|
||
menuUrl: 'https://iskelemarmaris.com/menu',
|
||
isFeatured: true
|
||
},
|
||
{
|
||
id: 'list-2',
|
||
slug: 'mavi-beyaz-restoran',
|
||
categoryId: 'cat-1',
|
||
neighborhoodId: 'neigh-1',
|
||
city: 'marmaris',
|
||
nameTr: 'Mavi Beyaz Restoran',
|
||
nameEn: 'Blue White Restaurant',
|
||
nameRu: 'Ресторан Сине-Белый',
|
||
descriptionTr: 'Ege kıyılarının esintisini taşıyan, deniz ürünleri ağırlıklı menüsü ve gün batımı eşliğindeki eşsiz mezeleriyle ünlüdür.',
|
||
descriptionEn: 'Famous for its seafood-oriented menu carrying the breeze of the Aegean coasts and unique appetizers accompanied by sunset.',
|
||
descriptionRu: 'Славится своим меню из морепродуктов, несущим бриз Эгейского побережья, и уникальными закусками на фоне заката.',
|
||
address: 'Kordon Caddesi No:45, Yat Limanı, Marmaris',
|
||
phone: '+90 252 412 78 90',
|
||
whatsapp: '+90 533 987 65 43',
|
||
website: 'https://mavibeyazmarmaris.com',
|
||
instagram: 'mavibeyaz_marmaris',
|
||
priceRange: 2,
|
||
rating: 4.5,
|
||
isLocalApproved: true,
|
||
latitude: 36.8530,
|
||
longitude: 28.2725,
|
||
openingHours: { all: '11:00 - 23:30' },
|
||
images: [
|
||
{ id: 'img-2-1', listingId: 'list-2', url: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 24 * 4),
|
||
updatedAt: new Date(),
|
||
menuUrl: 'https://mavibeyazmarmaris.com/digital-menu',
|
||
isFeatured: false
|
||
},
|
||
{
|
||
id: 'list-3',
|
||
slug: 'dostlar-kebap',
|
||
categoryId: 'cat-1',
|
||
neighborhoodId: 'neigh-3',
|
||
city: 'marmaris',
|
||
nameTr: 'Dostlar Kebap',
|
||
nameEn: 'Dostlar Kebab House',
|
||
nameRu: 'Кебаб Хаус Достлар',
|
||
descriptionTr: 'Marmaris Armutalan\'da yıllardır değişmeyen lezzetiyle gerçek ocakbaşı ve kebap deneyimi sunan samimi bir mahalle restoranı.',
|
||
descriptionEn: 'A cozy neighborhood restaurant offering real grill and kebab experience with its unchanged taste for years in Armutalan, Marmaris.',
|
||
descriptionRu: 'Уютный районный ресторан, предлагающий настоящий гриль и кебаб с неизменным вкусом на протяжении многих лет в Армуталане, Мармарис.',
|
||
address: 'Vatan Caddesi No:18, Armutalan, Marmaris',
|
||
phone: '+90 252 413 11 22',
|
||
whatsapp: null,
|
||
website: null,
|
||
instagram: 'dostlarkebap_marmaris',
|
||
priceRange: 1,
|
||
rating: 4.7,
|
||
isLocalApproved: false,
|
||
latitude: 36.8488,
|
||
longitude: 28.2450,
|
||
openingHours: { all: '11:00 - 22:00' },
|
||
images: [
|
||
{ id: 'img-3-1', listingId: 'list-3', url: 'https://images.unsplash.com/photo-1544025162-d76694265947?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 24 * 3),
|
||
updatedAt: new Date(),
|
||
isFeatured: false
|
||
},
|
||
{
|
||
id: 'list-4',
|
||
slug: 'zeytin-bahcesi-apart',
|
||
categoryId: 'cat-2',
|
||
neighborhoodId: 'neigh-3',
|
||
city: 'marmaris',
|
||
nameTr: 'Zeytin Bahçesi Apart',
|
||
nameEn: 'Olive Garden Apart',
|
||
nameRu: 'Апарт Оливковый Сад',
|
||
descriptionTr: 'Zeytin ağaçları arasında, sakin ve huzurlu bir ortamda ailece tatil yapmak isteyenler için tasarlanmış geniş mutfaklı apart daireler.',
|
||
descriptionEn: 'Spacious apart apartments with kitchens designed for families who want to have a holiday in a quiet and peaceful environment among olive trees.',
|
||
descriptionRu: 'Просторные апартаменты с кухнями, предназначенные для семей, желающих отдохнуть в тихой и спокойной обстановке среди оливковых деревьев.',
|
||
address: 'Zeytinlik Sokak No:5, Armutalan, Marmaris',
|
||
phone: '+90 252 413 55 66',
|
||
whatsapp: '+90 535 555 66 77',
|
||
website: 'https://zeytinbahcesiapart.com',
|
||
instagram: null,
|
||
priceRange: 2,
|
||
rating: 4.6,
|
||
isLocalApproved: true,
|
||
latitude: 36.8510,
|
||
longitude: 28.2415,
|
||
openingHours: null,
|
||
images: [
|
||
{ id: 'img-4-1', listingId: 'list-4', url: 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800&auto=format&fit=crop&q=80' },
|
||
{ id: 'img-4-2', listingId: 'list-4', url: 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 24 * 2),
|
||
updatedAt: new Date(),
|
||
isFeatured: true
|
||
},
|
||
{
|
||
id: 'list-5',
|
||
slug: 'deniz-apart',
|
||
categoryId: 'cat-2',
|
||
neighborhoodId: 'neigh-4',
|
||
city: 'marmaris',
|
||
nameTr: 'Deniz Apart',
|
||
nameEn: 'Sea Apart Hotel',
|
||
nameRu: 'Апарт-отель Дениз',
|
||
descriptionTr: 'Denize sadece 100 metre mesafede, bütçe dostu fiyatları ve güler yüzlü yerel işletme sahibiyle Marmaris\'te sıcak konaklama.',
|
||
descriptionEn: 'Cozy accommodation in Marmaris, just 100 meters from the sea, with budget-friendly prices and a friendly local owner.',
|
||
descriptionRu: 'Уютное жилье в Мармарисе, всего в 100 метрах от моря, с доступными ценами и дружелюбным местным владельцем.',
|
||
address: 'Sahil Yolu Caddesi No:88, Siteler, Marmaris',
|
||
phone: '+90 252 417 88 99',
|
||
whatsapp: null,
|
||
website: null,
|
||
instagram: null,
|
||
priceRange: 1,
|
||
rating: 4.2,
|
||
isLocalApproved: false,
|
||
latitude: 36.8375,
|
||
longitude: 28.2580,
|
||
openingHours: null,
|
||
images: [
|
||
{ id: 'img-5-1', listingId: 'list-5', url: 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 24 * 1),
|
||
updatedAt: new Date(),
|
||
isFeatured: false
|
||
},
|
||
{
|
||
id: 'list-6',
|
||
slug: 'marina-diving-center',
|
||
categoryId: 'cat-3',
|
||
neighborhoodId: 'neigh-1',
|
||
city: 'marmaris',
|
||
nameTr: 'Marina Dalış Merkezi',
|
||
nameEn: 'Marina Diving Center',
|
||
nameRu: 'Дайвинг-центр Марина',
|
||
descriptionTr: 'Marmaris\'in kristal netliğindeki sularında profesyonel eğitmenlerle dalış eğitimleri ve günlük dalış turları. CMAS ve PADI sertifikalı eğitimler.',
|
||
descriptionEn: 'Diving training and daily diving tours in the crystal clear waters of Marmaris with professional instructors. CMAS and PADI certified courses.',
|
||
descriptionRu: 'Обучение дайвингу и ежедневные дайв-туры в кристально чистых водах Мармариса с профессиональными инструкторами. Курсы с сертификатом CMAS и PADI.',
|
||
address: 'Yat Limanı Belediye İskelesi, Marmaris',
|
||
phone: '+90 532 234 56 78',
|
||
whatsapp: '+90 532 234 56 78',
|
||
website: 'https://marinadivingmarmaris.com',
|
||
instagram: null,
|
||
priceRange: 2,
|
||
rating: 4.9,
|
||
isLocalApproved: true,
|
||
latitude: 36.8521,
|
||
longitude: 28.2748,
|
||
openingHours: { all: '09:00 - 19:00' },
|
||
images: [
|
||
{ id: 'img-6-1', listingId: 'list-6', url: 'https://images.unsplash.com/photo-1544551763-46a013bb70d5?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 12),
|
||
updatedAt: new Date(),
|
||
isFeatured: false
|
||
},
|
||
{
|
||
id: 'list-7',
|
||
slug: 'aegean-wind-yacht-charter',
|
||
categoryId: 'cat-3',
|
||
neighborhoodId: 'neigh-1',
|
||
city: 'marmaris',
|
||
nameTr: 'Ege Rüzgarı Yat Kiralama',
|
||
nameEn: 'Aegean Wind Yacht Charter',
|
||
nameRu: 'Аренда Яхт Эгейский Ветер',
|
||
descriptionTr: 'Kaptanlı veya kaptansız olarak günlük ve haftalık özel tekne kiralama. Marmaris koylarını kendi rotanızla özgürce keşfedin.',
|
||
descriptionEn: 'Daily and weekly private boat charter with or without skipper. Discover the bays of Marmaris freely with your own route.',
|
||
descriptionRu: 'Ежедневная и еженедельная аренда частных лодок со шкипером или без. Откройте для себя бухты Мармариса свободно по собственному маршруту.',
|
||
address: 'Yat Limanı G İskelesi, Marmaris',
|
||
phone: '+90 532 999 88 77',
|
||
whatsapp: '+90 532 999 88 77',
|
||
website: 'https://egeruzgariboat.com',
|
||
instagram: 'egeruzgariboat',
|
||
priceRange: 3,
|
||
rating: 4.8,
|
||
isLocalApproved: true,
|
||
latitude: 36.8528,
|
||
longitude: 28.2755,
|
||
openingHours: { all: '08:00 - 21:00' },
|
||
images: [
|
||
{ id: 'img-7-1', listingId: 'list-7', url: 'https://images.unsplash.com/photo-1567899378494-47b22a2ae96a?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 6),
|
||
updatedAt: new Date(),
|
||
isFeatured: false
|
||
},
|
||
{
|
||
id: 'list-8',
|
||
slug: 'marmaris-transfer-tours',
|
||
categoryId: 'cat-3',
|
||
neighborhoodId: 'neigh-3',
|
||
city: 'marmaris',
|
||
nameTr: 'Marmaris VIP Transfer & Tur',
|
||
nameEn: 'Marmaris VIP Transfer & Tours',
|
||
nameRu: 'Marmaris VIP Трансфер и Туры',
|
||
descriptionTr: 'Dalaman Havalimanı transferleri ve Marmaris çevresindeki tarihi/doğal alanlara özel konforlu turlar. Güvenilir ve lüks taşımacılık.',
|
||
descriptionEn: 'Dalaman Airport transfers and comfortable private tours to historical/natural areas around Marmaris. Reliable and luxurious transportation.',
|
||
descriptionRu: 'Трансфер из аэропорта Даламан и комфортабельные частные туры по историческим и природным местам вокруг Мармариса. Надежный и роскошный транспорт.',
|
||
address: 'Atatürk Caddesi No:102, Armutalan, Marmaris',
|
||
phone: '+90 252 413 77 88',
|
||
whatsapp: '+90 541 333 44 55',
|
||
website: 'https://marmarisviptransfer.com',
|
||
instagram: null,
|
||
priceRange: 2,
|
||
rating: 4.6,
|
||
isLocalApproved: false,
|
||
latitude: 36.8495,
|
||
longitude: 28.2430,
|
||
openingHours: { all: '24 Hours Open' },
|
||
images: [
|
||
{ id: 'img-8-1', listingId: 'list-8', url: 'https://images.unsplash.com/photo-1549317661-bd32c8ce0db2?w=800&auto=format&fit=crop&q=80' }
|
||
],
|
||
createdAt: new Date(Date.now() - 3600000 * 2),
|
||
updatedAt: new Date(),
|
||
isFeatured: false
|
||
}
|
||
]
|
||
|
||
// Seed Blog Posts
|
||
globalForMockDb.blogPosts = [
|
||
{
|
||
id: 'post-1',
|
||
slug: 'marmariste-nerede-yenir-2026',
|
||
titleTr: 'Marmaris\'te Nerede Yenir? 2026 Lezzet Durakları',
|
||
titleEn: 'Where to Eat in Marmaris? 2026 Culinary Hotspots',
|
||
titleRu: 'Где поесть в Мармарисе? Лучшие места 2026 года',
|
||
contentTr: 'Marmaris, Ege ve Akdeniz mutfağının en taze deniz ürünlerini ve mezelerini bulabileceğiniz harika bir sahil kenti. İşte 2026 yılında ziyaret etmeniz gereken en lezzetli mekanlar...\n\n### 1. İskele Balık Ocakbaşı\nYat Limanında yer alan bu harika mekan, taze balıkları ve mezeleriyle ünlüdür.\n\n### 2. Mavi Beyaz Restoran\nSöğüt köyündeki eşsiz manzarası ve gurme Ege yemekleri ile unutulmaz bir akşam sunuyor.',
|
||
contentEn: 'Marmaris is a wonderful coastal town where you can find the freshest seafood and appetizers of Aegean and Mediterranean cuisine. Here are the most delicious places you should visit in 2026...\n\n### 1. Iskele Fish & Grill\nLocated in Yat Limani, this wonderful venue is famous for its fresh fish and appetizers.\n\n### 2. Mavi Beyaz Restaurant\nOffers an unforgettable evening with its unique view and gourmet Aegean dishes in Sogut village.',
|
||
contentRu: 'Мармарис — прекрасный прибрежный город, где вы найдете самые свежие морепродукты и закуски эгейской и средиземноморской кухни. Вот самые вкусные места, которые стоит посетить в 2026 году...\n\n### 1. Искеле Балык Оджакбаши\nЭто замечательное заведение, расположенное в Ят Лимани, славится свежей рыбой и закусками.\n\n### 2. Ресторан Мави Беяз\nПредлагает незабываемый вечер с уникальным видом и изысканными блюдами эгейской кухни в деревне Сегют.',
|
||
coverImage: 'https://images.unsplash.com/photo-1504674900247-0877df9cc836?w=1200&auto=format&fit=crop&q=80',
|
||
tags: ['Restoran', 'Yemek', 'Rehber'],
|
||
relatedListingIds: ['list-1', 'list-2'],
|
||
publishedAt: new Date(),
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
},
|
||
{
|
||
id: 'post-2',
|
||
slug: 'gun-batimi-icin-5-mekan',
|
||
titleTr: 'Marmaris\'te Gün Batımını İzleyebileceğiniz En İyi 5 Yer',
|
||
titleEn: 'Top 5 Places to Watch the Sunset in Marmaris',
|
||
titleRu: '5 лучших мест для наблюдения за закатом в Мармарисе',
|
||
contentTr: 'Marmaris\'in en büyüleyici anlarından biri hiç şüphesiz gün batımıdır. Gökyüzünün kızıla büründüğü bu saatlerde unutulmaz kareler yakalayabileceğiniz ve keyifle içeceğinizi yudumlayabileceğiniz en güzel yerleri derledik.\n\n* **Yat Limanı:** Şehir merkezinde en popüler seyir yeri.\n* **İçmeler Sahili:** Adaların arkasından batan güneşi izlemek şahanedir.\n* **Turunç Tepesi:** Kuşbakışı körfez manzarası sunar.',
|
||
contentEn: 'One of the most fascinating moments of Marmaris is undoubtedly the sunset. We have compiled the most beautiful places where you can capture unforgettable frames and enjoy your drink while the sky turns red.\n\n* **Marina:** The most popular viewing point in the city center.\n* **Icmeler Beach:** It is wonderful to watch the sun setting behind the islands.\n* **Turunc Hill:** Offers a panoramic view of the bay.',
|
||
contentRu: 'Один из самых захватывающих моментов в Мармарисе — это, без сомнения, закат. Мы собрали самые красивые места, где вы сможете сделать незабываемые снимки и насладиться напитком, пока небо окрашивается в красный цвет.\n\n* **Марина:** Самая популярная точка обзора в центре города.\n* **Пляж Ичмелер:** Прекрасно наблюдать за закатом солнца за островами.\n* **Холм Турунч:** Панорамный вид на залив.',
|
||
coverImage: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=1200&auto=format&fit=crop&q=80',
|
||
tags: ['Manzara', 'Gezi', 'Gün Batımı'],
|
||
relatedListingIds: ['list-2', 'list-7'],
|
||
publishedAt: new Date(),
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
}
|
||
]
|
||
|
||
// Seed Collections
|
||
globalForMockDb.collections = [
|
||
{
|
||
id: 'col-1',
|
||
slug: 'aile-dostu-restoranlar',
|
||
titleTr: 'Aile Dostu Restoranlar',
|
||
titleEn: 'Family Friendly Restaurants',
|
||
titleRu: 'Семейные рестораны',
|
||
descriptionTr: 'Çocuklarınızla birlikte rahatça yemek yiyebileceğiniz, oyun alanları ve özel çocuk menüleri bulunan en iyi Marmaris mekanları.',
|
||
descriptionEn: 'The best Marmaris restaurants with playgrounds and special kids\' menus where you can comfortably dine with your children.',
|
||
descriptionRu: 'Лучшие рестораны Мармариса с детскими площадками и специальным детским меню, где вы сможете комфортно пообедать с детьми.',
|
||
coverImage: 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=1200&auto=format&fit=crop&q=80',
|
||
listingIds: ['list-1', 'list-3'],
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
},
|
||
{
|
||
id: 'col-2',
|
||
slug: 'butce-dostu-mekanlar',
|
||
titleTr: 'Bütçe Dostu Mekanlar',
|
||
titleEn: 'Budget-Friendly Venues',
|
||
titleRu: 'Бюджетные заведения',
|
||
descriptionTr: 'Marmaris tatilinizde cebinizi yormayacak, hem kaliteli hizmet sunan hem de uygun fiyatlı lokasyonlar.',
|
||
descriptionEn: 'Budget-friendly locations in Marmaris that offer high-quality service and reasonable prices for your holiday.',
|
||
descriptionRu: 'Доступные заведения в Мармарисе, которые предлагают высококачественный сервис и умеренные цены во время вашего отдыха.',
|
||
coverImage: 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=1200&auto=format&fit=crop&q=80',
|
||
listingIds: ['list-3', 'list-5'],
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
}
|
||
]
|
||
|
||
// Seed Instagram Caches
|
||
globalForMockDb.instagramFeedCaches = [
|
||
{
|
||
id: 'insta-1',
|
||
listingId: 'list-1',
|
||
handle: 'iskele_marmaris',
|
||
posts: [
|
||
{ imageUrl: 'https://images.unsplash.com/photo-1544025162-d76694265947?w=500&auto=format&fit=crop&q=80', caption: 'Mezelerimiz taze taze hazırlandı! 🐟', permalink: '#', postedAt: '2026-07-10T12:00:00Z' },
|
||
{ imageUrl: 'https://images.unsplash.com/photo-1519708227418-c8fd9a32b7a2?w=500&auto=format&fit=crop&q=80', caption: 'Bu akşam iskelede gün batımı bir başka güzel... 🌅', permalink: '#', postedAt: '2026-07-09T18:30:00Z' },
|
||
{ imageUrl: 'https://images.unsplash.com/photo-1476224203421-9ac39bcb3327?w=500&auto=format&fit=crop&q=80', caption: 'Balık keyfini kaçırmayın! 🍽️', permalink: '#', postedAt: '2026-07-08T14:15:00Z' }
|
||
],
|
||
fetchedAt: new Date()
|
||
},
|
||
{
|
||
id: 'insta-2',
|
||
listingId: 'list-2',
|
||
handle: 'mavibeyaz_marmaris',
|
||
posts: [
|
||
{ imageUrl: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=500&auto=format&fit=crop&q=80', caption: 'Kordon keyfi... 🍷', permalink: '#', postedAt: '2026-07-11T16:00:00Z' },
|
||
{ imageUrl: 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=500&auto=format&fit=crop&q=80', caption: 'Taze deniz ürünleri ve meze çeşitleri Mavi Beyaz\'da!', permalink: '#', postedAt: '2026-07-08T15:30:00Z' }
|
||
],
|
||
fetchedAt: new Date()
|
||
}
|
||
]
|
||
|
||
globalForMockDb.initialized = true
|
||
}
|
||
|
||
export const mockDb = {
|
||
// Config helpers
|
||
isMock: () => process.env.USE_MOCK === 'true',
|
||
|
||
// Categories
|
||
async getCategories() {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.categories
|
||
}
|
||
return db.category.findMany({ orderBy: { id: 'asc' } })
|
||
},
|
||
|
||
async getCategoryBySlug(slug: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.categories.find(c => c.slug === slug) || null
|
||
}
|
||
return db.category.findUnique({ where: { slug } })
|
||
},
|
||
|
||
async getCategoryById(id: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.categories.find(c => c.id === id) || null
|
||
}
|
||
return db.category.findUnique({ where: { id } })
|
||
},
|
||
|
||
// Neighborhoods
|
||
async getNeighborhoods() {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.neighborhoods
|
||
}
|
||
return db.neighborhood.findMany({ orderBy: { id: 'asc' } })
|
||
},
|
||
|
||
async getNeighborhoodBySlug(slug: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.neighborhoods.find(n => n.slug === slug) || null
|
||
}
|
||
return db.neighborhood.findUnique({ where: { slug } })
|
||
},
|
||
|
||
async getNeighborhoodById(id: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.neighborhoods.find(n => n.id === id) || null
|
||
}
|
||
return db.neighborhood.findUnique({ where: { id } })
|
||
},
|
||
|
||
// Listings CRUD
|
||
async getListings(filters?: {
|
||
categoryId?: string
|
||
neighborhoodId?: string
|
||
priceRange?: number
|
||
isLocalApproved?: boolean
|
||
search?: string
|
||
isFeatured?: boolean
|
||
}) {
|
||
if (this.isMock()) {
|
||
let result = [...globalForMockDb.listings].filter(l => !l.deletedAt)
|
||
if (filters) {
|
||
if (filters.categoryId) result = result.filter(l => l.categoryId === filters.categoryId)
|
||
if (filters.neighborhoodId) result = result.filter(l => l.neighborhoodId === filters.neighborhoodId)
|
||
if (filters.priceRange) result = result.filter(l => l.priceRange === filters.priceRange)
|
||
if (filters.isLocalApproved !== undefined) result = result.filter(l => l.isLocalApproved === filters.isLocalApproved)
|
||
if (filters.isFeatured !== undefined) result = result.filter(l => l.isFeatured === filters.isFeatured)
|
||
if (filters.search) {
|
||
const s = filters.search.toLowerCase()
|
||
result = result.filter(
|
||
l =>
|
||
l.nameTr.toLowerCase().includes(s) ||
|
||
l.nameEn.toLowerCase().includes(s) ||
|
||
l.nameRu.toLowerCase().includes(s) ||
|
||
l.address.toLowerCase().includes(s)
|
||
)
|
||
}
|
||
}
|
||
|
||
// Sort: Featured items first, then newer listings first
|
||
result.sort((a, b) => {
|
||
if (a.isFeatured && !b.isFeatured) return -1
|
||
if (!a.isFeatured && b.isFeatured) return 1
|
||
return b.createdAt.getTime() - a.createdAt.getTime()
|
||
})
|
||
|
||
return result.map(l => ({
|
||
...l,
|
||
category: globalForMockDb.categories.find(c => c.id === l.categoryId),
|
||
neighborhood: globalForMockDb.neighborhoods.find(n => n.id === l.neighborhoodId)
|
||
}))
|
||
}
|
||
|
||
const where: any = { deletedAt: null }
|
||
if (filters) {
|
||
if (filters.categoryId) where.categoryId = filters.categoryId
|
||
if (filters.neighborhoodId) where.neighborhoodId = filters.neighborhoodId
|
||
if (filters.priceRange) where.priceRange = filters.priceRange
|
||
if (filters.isLocalApproved !== undefined) where.isLocalApproved = filters.isLocalApproved
|
||
if (filters.isFeatured !== undefined) where.isFeatured = filters.isFeatured
|
||
if (filters.search) {
|
||
where.OR = [
|
||
{ nameTr: { contains: filters.search, mode: 'insensitive' } },
|
||
{ nameEn: { contains: filters.search, mode: 'insensitive' } },
|
||
{ nameRu: { contains: filters.search, mode: 'insensitive' } },
|
||
{ address: { contains: filters.search, mode: 'insensitive' } },
|
||
]
|
||
}
|
||
}
|
||
|
||
return db.listing.findMany({
|
||
where,
|
||
include: { category: true, neighborhood: true, images: true },
|
||
orderBy: [
|
||
{ isFeatured: 'desc' },
|
||
{ createdAt: 'desc' }
|
||
]
|
||
})
|
||
},
|
||
|
||
async getListingBySlug(slug: string) {
|
||
if (this.isMock()) {
|
||
const listing = globalForMockDb.listings.find(l => l.slug === slug && !l.deletedAt)
|
||
if (!listing) return null
|
||
return {
|
||
...listing,
|
||
category: globalForMockDb.categories.find(c => c.id === listing.categoryId),
|
||
neighborhood: globalForMockDb.neighborhoods.find(n => n.id === listing.neighborhoodId)
|
||
}
|
||
}
|
||
return db.listing.findUnique({
|
||
where: { slug },
|
||
include: { category: true, neighborhood: true, images: true }
|
||
})
|
||
},
|
||
|
||
async getListingById(id: string) {
|
||
if (this.isMock()) {
|
||
const listing = globalForMockDb.listings.find(l => l.id === id && !l.deletedAt)
|
||
if (!listing) return null
|
||
return {
|
||
...listing,
|
||
category: globalForMockDb.categories.find(c => c.id === listing.categoryId),
|
||
neighborhood: globalForMockDb.neighborhoods.find(n => n.id === listing.neighborhoodId)
|
||
}
|
||
}
|
||
return db.listing.findUnique({
|
||
where: { id },
|
||
include: { category: true, neighborhood: true, images: true }
|
||
})
|
||
},
|
||
|
||
async createListing(data: Omit<Listing, 'id' | 'images' | 'createdAt' | 'updatedAt'> & { images?: string[] }) {
|
||
const { images, category, neighborhood, ...rest } = data
|
||
if (this.isMock()) {
|
||
const newId = `list-${Date.now()}`
|
||
const gallery = (images || []).map((url, i) => ({ id: `img-${newId}-${i}`, listingId: newId, url }))
|
||
const newListing: Listing = {
|
||
id: newId,
|
||
...rest,
|
||
images: gallery,
|
||
createdAt: new Date(),
|
||
updatedAt: new Date(),
|
||
isFeatured: data.isFeatured || false
|
||
}
|
||
globalForMockDb.listings.push(newListing)
|
||
return newListing
|
||
}
|
||
return db.listing.create({
|
||
data: {
|
||
...rest,
|
||
images: {
|
||
create: (images || []).map(url => ({ url }))
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
async updateListing(id: string, data: Partial<Omit<Listing, 'id' | 'images' | 'createdAt' | 'updatedAt'>> & { images?: string[] }) {
|
||
const { images, category, neighborhood, ...rest } = data
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.listings.findIndex(l => l.id === id)
|
||
if (idx !== -1) {
|
||
const gallery = images ? images.map((url, i) => ({ id: `img-${id}-${i}`, listingId: id, url })) : globalForMockDb.listings[idx].images
|
||
globalForMockDb.listings[idx] = {
|
||
...globalForMockDb.listings[idx],
|
||
...rest,
|
||
images: gallery,
|
||
updatedAt: new Date()
|
||
} as Listing
|
||
return globalForMockDb.listings[idx]
|
||
}
|
||
return null
|
||
}
|
||
|
||
// Update listing images transaction
|
||
if (images) {
|
||
await db.gallery.deleteMany({ where: { listingId: id } })
|
||
return db.listing.update({
|
||
where: { id },
|
||
data: {
|
||
...rest,
|
||
images: {
|
||
create: images.map(url => ({ url }))
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
return db.listing.update({
|
||
where: { id },
|
||
data: rest
|
||
})
|
||
},
|
||
|
||
async deleteListing(id: string) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.listings.findIndex(l => l.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.listings[idx].deletedAt = new Date()
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
await db.listing.update({
|
||
where: { id },
|
||
data: { deletedAt: new Date() }
|
||
})
|
||
return true
|
||
},
|
||
|
||
// Business Submissions
|
||
async getSubmissions() {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.submissions.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
||
}
|
||
return db.businessSubmission.findMany({ orderBy: { createdAt: 'desc' } })
|
||
},
|
||
|
||
async createSubmission(data: Omit<BusinessSubmission, 'id' | 'status' | 'createdAt' | 'updatedAt'>) {
|
||
if (this.isMock()) {
|
||
const newSub: BusinessSubmission = {
|
||
id: `sub-${Date.now()}`,
|
||
...data,
|
||
status: 'PENDING',
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
}
|
||
globalForMockDb.submissions.push(newSub)
|
||
return newSub
|
||
}
|
||
return db.businessSubmission.create({ data: { ...data, status: 'PENDING' } })
|
||
},
|
||
|
||
async updateSubmissionStatus(id: string, status: 'APPROVED' | 'REJECTED') {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.submissions.findIndex(s => s.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.submissions[idx].status = status
|
||
globalForMockDb.submissions[idx].updatedAt = new Date()
|
||
return globalForMockDb.submissions[idx]
|
||
}
|
||
return null
|
||
}
|
||
return db.businessSubmission.update({
|
||
where: { id },
|
||
data: { status }
|
||
})
|
||
},
|
||
|
||
async getSubmissionById(id: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.submissions.find(s => s.id === id) || null
|
||
}
|
||
return db.businessSubmission.findUnique({ where: { id } })
|
||
},
|
||
|
||
// Contact Messages
|
||
async getMessages() {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.messages.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
||
}
|
||
return db.contactMessage.findMany({ orderBy: { createdAt: 'desc' } })
|
||
},
|
||
|
||
async createMessage(data: Omit<ContactMessage, 'id' | 'isRead' | 'createdAt' | 'updatedAt'>) {
|
||
if (this.isMock()) {
|
||
const newMsg: ContactMessage = {
|
||
id: `msg-${Date.now()}`,
|
||
...data,
|
||
isRead: false,
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
}
|
||
globalForMockDb.messages.push(newMsg)
|
||
return newMsg
|
||
}
|
||
return db.contactMessage.create({ data: { ...data, isRead: false } })
|
||
},
|
||
|
||
async markMessageAsRead(id: string) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.messages.findIndex(m => m.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.messages[idx].isRead = true
|
||
globalForMockDb.messages[idx].updatedAt = new Date()
|
||
return globalForMockDb.messages[idx]
|
||
}
|
||
return null
|
||
}
|
||
return db.contactMessage.update({
|
||
where: { id },
|
||
data: { isRead: true }
|
||
})
|
||
},
|
||
|
||
// BlogPost CRUD (Phase 2)
|
||
async getBlogPosts(onlyPublished: boolean = false) {
|
||
if (this.isMock()) {
|
||
let posts = globalForMockDb.blogPosts.filter(p => !p.deletedAt)
|
||
if (onlyPublished) {
|
||
posts = posts.filter(p => p.publishedAt !== null)
|
||
}
|
||
return posts.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
||
}
|
||
const where: any = { deletedAt: null }
|
||
if (onlyPublished) {
|
||
where.publishedAt = { not: null }
|
||
}
|
||
return db.blogPost.findMany({
|
||
where,
|
||
orderBy: { createdAt: 'desc' }
|
||
})
|
||
},
|
||
|
||
async getBlogPostBySlug(slug: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.blogPosts.find(p => p.slug === slug && !p.deletedAt) || null
|
||
}
|
||
return db.blogPost.findUnique({ where: { slug } })
|
||
},
|
||
|
||
async getBlogPostById(id: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.blogPosts.find(p => p.id === id && !p.deletedAt) || null
|
||
}
|
||
return db.blogPost.findUnique({ where: { id } })
|
||
},
|
||
|
||
async createBlogPost(data: Omit<BlogPost, 'id' | 'createdAt' | 'updatedAt'>) {
|
||
if (this.isMock()) {
|
||
const newPost: BlogPost = {
|
||
id: `post-${Date.now()}`,
|
||
...data,
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
}
|
||
globalForMockDb.blogPosts.push(newPost)
|
||
return newPost
|
||
}
|
||
return db.blogPost.create({ data })
|
||
},
|
||
|
||
async updateBlogPost(id: string, data: Partial<Omit<BlogPost, 'id' | 'createdAt' | 'updatedAt'>>) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.blogPosts.findIndex(p => p.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.blogPosts[idx] = {
|
||
...globalForMockDb.blogPosts[idx],
|
||
...data,
|
||
updatedAt: new Date()
|
||
}
|
||
return globalForMockDb.blogPosts[idx]
|
||
}
|
||
return null
|
||
}
|
||
return db.blogPost.update({ where: { id }, data })
|
||
},
|
||
|
||
async deleteBlogPost(id: string) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.blogPosts.findIndex(p => p.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.blogPosts[idx].deletedAt = new Date()
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
await db.blogPost.update({ where: { id }, data: { deletedAt: new Date() } })
|
||
return true
|
||
},
|
||
|
||
// Collection CRUD (Phase 2)
|
||
async getCollections() {
|
||
if (this.isMock()) {
|
||
const colls = [...globalForMockDb.collections]
|
||
return colls.map(c => ({
|
||
...c,
|
||
listings: globalForMockDb.listings.filter(l => c.listingIds.includes(l.id) && !l.deletedAt)
|
||
}))
|
||
}
|
||
return db.collection.findMany({
|
||
include: { listings: { include: { images: true, category: true, neighborhood: true } } },
|
||
orderBy: { createdAt: 'desc' }
|
||
})
|
||
},
|
||
|
||
async getCollectionBySlug(slug: string) {
|
||
if (this.isMock()) {
|
||
const c = globalForMockDb.collections.find(col => col.slug === slug)
|
||
if (!c) return null
|
||
return {
|
||
...c,
|
||
listings: globalForMockDb.listings.filter(l => c.listingIds.includes(l.id) && !l.deletedAt).map(l => ({
|
||
...l,
|
||
category: globalForMockDb.categories.find(cat => cat.id === l.categoryId),
|
||
neighborhood: globalForMockDb.neighborhoods.find(n => n.id === l.neighborhoodId)
|
||
}))
|
||
}
|
||
}
|
||
return db.collection.findUnique({
|
||
where: { slug },
|
||
include: { listings: { include: { images: true, category: true, neighborhood: true } } }
|
||
})
|
||
},
|
||
|
||
async getCollectionById(id: string) {
|
||
if (this.isMock()) {
|
||
const c = globalForMockDb.collections.find(col => col.id === id)
|
||
if (!c) return null
|
||
return {
|
||
...c,
|
||
listings: globalForMockDb.listings.filter(l => c.listingIds.includes(l.id) && !l.deletedAt)
|
||
}
|
||
}
|
||
return db.collection.findUnique({
|
||
where: { id },
|
||
include: { listings: true }
|
||
})
|
||
},
|
||
|
||
async createCollection(data: Omit<Collection, 'id' | 'createdAt' | 'updatedAt' | 'listings'>) {
|
||
if (this.isMock()) {
|
||
const newCol: Collection = {
|
||
id: `col-${Date.now()}`,
|
||
...data,
|
||
createdAt: new Date(),
|
||
updatedAt: new Date()
|
||
}
|
||
globalForMockDb.collections.push(newCol)
|
||
return newCol
|
||
}
|
||
const { listingIds, ...rest } = data
|
||
return db.collection.create({
|
||
data: {
|
||
...rest,
|
||
listings: {
|
||
connect: listingIds.map(id => ({ id }))
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
async updateCollection(id: string, data: Partial<Omit<Collection, 'id' | 'createdAt' | 'updatedAt' | 'listings'>>) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.collections.findIndex(c => c.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.collections[idx] = {
|
||
...globalForMockDb.collections[idx],
|
||
...data,
|
||
updatedAt: new Date()
|
||
} as Collection
|
||
return globalForMockDb.collections[idx]
|
||
}
|
||
return null
|
||
}
|
||
const { listingIds, ...rest } = data
|
||
if (listingIds) {
|
||
// For actual DB, first disconnect all and connect new
|
||
const current = await db.collection.findUnique({ where: { id }, include: { listings: true } })
|
||
const disconnectIds = current?.listings.map(l => ({ id: l.id })) || []
|
||
return db.collection.update({
|
||
where: { id },
|
||
data: {
|
||
...rest,
|
||
listings: {
|
||
disconnect: disconnectIds,
|
||
connect: listingIds.map(lid => ({ id: lid }))
|
||
}
|
||
}
|
||
})
|
||
}
|
||
return db.collection.update({ where: { id }, data: rest as any })
|
||
},
|
||
|
||
async deleteCollection(id: string) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.collections.findIndex(c => c.id === id)
|
||
if (idx !== -1) {
|
||
globalForMockDb.collections.splice(idx, 1)
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
await db.collection.delete({ where: { id } })
|
||
return true
|
||
},
|
||
|
||
// Instagram Feed Cache (Phase 2)
|
||
async getInstagramFeedCacheByListingId(listingId: string) {
|
||
if (this.isMock()) {
|
||
return globalForMockDb.instagramFeedCaches.find(cache => cache.listingId === listingId) || null
|
||
}
|
||
return db.instagramFeedCache.findUnique({ where: { listingId } })
|
||
},
|
||
|
||
async updateInstagramFeedCache(listingId: string, handle: string, posts: any[]) {
|
||
if (this.isMock()) {
|
||
const idx = globalForMockDb.instagramFeedCaches.findIndex(cache => cache.listingId === listingId)
|
||
if (idx !== -1) {
|
||
globalForMockDb.instagramFeedCaches[idx].handle = handle
|
||
globalForMockDb.instagramFeedCaches[idx].posts = posts
|
||
globalForMockDb.instagramFeedCaches[idx].fetchedAt = new Date()
|
||
return globalForMockDb.instagramFeedCaches[idx]
|
||
} else {
|
||
const newCache = {
|
||
id: `insta-${Date.now()}`,
|
||
listingId,
|
||
handle,
|
||
posts,
|
||
fetchedAt: new Date()
|
||
}
|
||
globalForMockDb.instagramFeedCaches.push(newCache)
|
||
return newCache
|
||
}
|
||
}
|
||
return db.instagramFeedCache.upsert({
|
||
where: { listingId },
|
||
update: { handle, posts, fetchedAt: new Date() },
|
||
create: { listingId, handle, posts, fetchedAt: new Date() }
|
||
})
|
||
}
|
||
}
|