stuff done

This commit is contained in:
2025-03-11 02:54:09 +02:00
parent 58e7ed2f06
commit 516b45fad9
90 changed files with 2950 additions and 9458 deletions

View File

@@ -1,6 +1,6 @@
export const BaseEditorConfig = {
readonly: false, // all options from https://xdsoft.net/jodit/docs/,
placeholder: 'Start typings...',
placeholder: 'Почніть введення...',
spellcheck: true,
language: 'ua',
//toolbarAdaptive: false,
@@ -10,9 +10,9 @@ export const BaseEditorConfig = {
//defaultActionOnPaste: 'insert_as_text',
//defaultActionOnPaste: 'insert_only_text',
//disablePlugins: 'ai-assistant,mobile,print,speech-recognize,table,table-keyboard-navigation,powered-by-jodit,iframe',
minHeight: 240,
maxHeight: 640,
maxWidth: 890,
minHeight: '240',
maxHeight: '640',
maxWidth: '890',
uploader: {
insertImageAsBase64URI: true,
imagesExtensions: ['jpg', 'png', 'jpeg', 'gif', 'svg', 'webp']

View File

@@ -0,0 +1,32 @@
model Entity {
id Int @id @default(autoincrement())
type EntityType
published Boolean? @default(false)
scopes Json?
position Int? @default(0) @db.UnsignedSmallInt
slug String? @db.VarChar(512)
media String? @db.VarChar(512)
storeId Int @default(1) @map("store_id")
locales EntityLocale[]
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3)
updatedAt DateTime? @default(dbgenerated("NULL DEFAULT NULL ON UPDATE current_timestamp(3)")) @map("updated_at") @db.Timestamp(3)
@@unique([storeId, type, slug])
@@map("entities")
}
model EntityLocale {
id Int @id @default(autoincrement())
lang Lang @default(uk)
slug String? @db.VarChar(512)
title String @db.VarChar(384)
annotation String? @db.MediumText
body String? @db.MediumText
entity Entity @relation(fields: [entityId], references: [id], onDelete: Cascade)
entityId Int @map("entity_id")
meta Meta? @relation(fields: [metaId], references: [id], onDelete: Cascade)
metaId Int? @map("meta_id")
@@unique([slug, lang])
@@map("entity_locale")
}

View File

@@ -1,8 +1,20 @@
enum DeliveryOption {
NP
PICKUP
COURIER
}
enum Lang {
uk
ru
}
enum EntityType {
article
block
page
}
enum Unit {
mkg
mg

View File

@@ -23,6 +23,7 @@ model Meta {
openGraph OpenGraph?
storeLocale StoreLocale[]
productLocale ProductLocale[]
entityLocale EntityLocale[]
//vendorLocale VendorLocale[]
@@map("meta")

View File

@@ -0,0 +1,26 @@
model Order {
id Int @id @default(autoincrement())
storeId Int @default(1) @map("store_id")
lang Lang
orderNo String @map("order_no") @db.VarChar(45)
isQuick Boolean @map("is_quick")
user User? @relation(fields: [userId], references: [id])
userId Int? @map("user_id")
firstName String @map("first_name") @db.VarChar(255)
patronymic String? @db.VarChar(255)
surname String? @db.VarChar(255)
deliveryOption DeliveryOption? @map("delivery_option")
phone String? @db.Char(24)
email String? @db.VarChar(320)
emailSent Boolean? @map("email_sent")
/// [OrderAddressType]
address Json?
notes String? @db.MediumText
/// [OrderDetailsType]
details Json
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3)
updatedAt DateTime? @default(dbgenerated("NULL DEFAULT NULL ON UPDATE current_timestamp(3)")) @map("updated_at") @db.Timestamp(3)
@@unique([orderNo, storeId])
@@map("orders")
}

View File

@@ -27,6 +27,7 @@ model User {
extendedData Json? @map("extended_data") @db.Json
// orders Order[]
favorites UserFavouriteProduct[]
orders Order[]
reviews UserProductReview[]
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(3)
updatedAt DateTime? @default(dbgenerated("NULL DEFAULT NULL ON UPDATE current_timestamp(3)")) @map("updated_at") @db.Timestamp(3)

88
lib/nova-post-helper.ts Normal file
View File

@@ -0,0 +1,88 @@
import cache from 'next/cache'
export const NP_SETTLEMENT_KYIV_REF = 'e718a680-4b33-11e4-ab6d-005056801329'
export type Street = {
SettlementStreetRef: string
Present: string
StreetsTypeDescription: string
SettlementStreetDescription: string
SettlementStreetDescriptionRu: string
}
export type Settlement = {
Ref: string
Description: string
DescriptionRu: string
AreaDescription: string
AreaDescriptionRu: string
SettlementTypeDescription: string
SettlementTypeDescriptionRu: string
}
export type Warehouse = {
Ref: string
Description: string
DescriptionRu: string
CityDescription: string
CityDescriptionRu: string
SettlementDescription: string
AreaDescription: string
SettlementRegionsDescription: string
SettlementTypeDescription: string
SettlementTypeDescriptionRu: string
Longitude: string
Latitude: string
}
export const getApi = async (url: string) => {
//TODO: need implement caching
return await fetch(url)
}
export const formatSettlement = (
city: Settlement,
locale: string = 'uk'
): string => {
if (!city) return ''
if (locale === 'ru') {
const {DescriptionRu, AreaDescriptionRu, SettlementTypeDescriptionRu} = city
// https://www.alta.ru/fias/socrname/
const type = SettlementTypeDescriptionRu.replace(
'поселок городского типа',
'пгт '
)
.replace('поселок', 'п. ')
.replace('село', 'с. ')
.replace('город', 'г. ')
return (
type +
DescriptionRu.replace(`(${AreaDescriptionRu} обл.)`, '')
.replace(`(${AreaDescriptionRu} обл)`, '')
.replace(`${AreaDescriptionRu} обл., `, '')
.trim() +
` (${AreaDescriptionRu} обл.)`
)
} else {
const {Description, AreaDescription, SettlementTypeDescription} = city
const type = SettlementTypeDescription.replace(
'селище міського типу',
'смт '
)
.replace('село', 'с. ')
.replace('селище', 'с-ще ')
.replace('місто', 'м. ')
return (
type +
Description.replace(`(${AreaDescription} обл.)`, '')
.replace(`(${AreaDescription} обл)`, '')
.replace(`(село)`, '')
.replace(`${AreaDescription} обл., `, '')
.trim() +
` (${AreaDescription} обл.)`
)
}
}

View File

@@ -1,7 +1,5 @@
import {z} from 'zod'
import {db} from '@/lib/db/prisma/client'
export const categoryLocaleSchema = z.object({
lang: z.enum(['uk', 'ru']),
title: z.string().trim().min(1).max(384),

View File

@@ -0,0 +1,43 @@
import {Entity, EntityLocale, EntityType} from '@prisma/client'
import {z} from 'zod'
import {i18nLocalesCodes} from '@/i18n-config'
import {metaFormSchema} from '@/lib/schemas/meta'
interface Map {
[key: string]: string | undefined
}
export const EntityTypeDescription: Map = {
article: 'Стаття',
page: 'Сторінка',
block: 'Блок'
}
//
export type EntityTerm = Entity & {locales: EntityLocale}
export const entityLocaleSchema = z.object({
lang: z.enum(i18nLocalesCodes),
title: z.coerce.string().trim().min(1).max(384),
annotation: z.coerce.string().trim().optional(),
body: z.coerce.string().trim().optional()
})
export const createEntityFormSchema = z.object({
type: z.enum(Object.keys(EntityType) as [string, ...string[]], {
message: "Обов'язкове до вибору"
}), // ProductToStore
published: z.coerce.boolean().default(false).optional(), // ProductToStore
scopes: z.coerce.string().trim().optional(),
slug: z.coerce
.string()
.trim()
.max(512)
.regex(/^[a-z0-9-]+$/, {
message: 'тільки латинські символи, цифри та дефіс'
})
.optional(),
media: z.coerce.string().trim().max(512).optional(),
locales: z.array(entityLocaleSchema),
meta: z.array(metaFormSchema)
})

View File

@@ -0,0 +1,38 @@
import {DeliveryOption, Lang, Order} from '@prisma/client'
import {z} from 'zod'
interface Map {
[key: string]: string | undefined
}
export const DeliveryOptionTypeDescription: Map = {
NP: 'До відділення «Нової Пошти»',
PICKUP: 'Самовивіз (для Києва)',
COURIER: "Кур'єр (для Києва)"
}
export const createOrderFormSchema = z.object({
user_id: z.string().optional(),
is_quick: z.boolean(),
lang: z.enum(Object.keys(Lang) as [string, ...string[]]),
first_name: z.coerce.string().trim().min(1).max(255),
//patronymic: z.coerce.string().trim().min(1).max(255),
surname: z.coerce.string().trim().min(1).max(255),
delivery_option: z.enum(
Object.keys(DeliveryOption) as [string, ...string[]],
{
message: "Обов'язкове до вибору"
}
),
phone: z.coerce.string().trim().min(1).max(24),
email: z.coerce
.string()
.trim()
.regex(/^[A-Za-z0-9\._%+\-]+@[A-Za-z0-9\.\-]+\.[A-Za-z]{2,}$/, {
message: 'Ведуть коректну e-mail адресу'
})
.max(320),
address: z.coerce.string().trim(),
notes: z.coerce.string().trim().max(1024).optional(),
details: z.coerce.string().trim()
})

View File

@@ -3,6 +3,7 @@ import bcrypt from 'bcryptjs'
import {type ClassValue, clsx} from 'clsx'
import {getLocale} from 'next-intl/server'
import slugify from 'slugify'
import striptags from 'striptags'
import {twMerge} from 'tailwind-merge'
import {i18nDefaultLocale} from '@/i18n-config'
@@ -157,3 +158,40 @@ export const dbErrorHandling = (e: unknown, message?: string | null) => {
*/
export const isEmptyObj = (obj: object): boolean =>
Object.keys(obj).length === 0
/**
* To convert letter on typing from latin to cyr
* TODO: need to complete
*
* @param term
*/
export const replacerLat2Cyr = (term: string): string => {
const obj = {g: 'п', e: 'у', o: 'щ', f: 'а'}
return term
.split('')
.map((ch: PropertyKey): string => {
return obj.hasOwnProperty(ch as PropertyKey)
? (obj[ch as never] as string)
: (ch as string)
})
.join('')
}
type NormalizeConfigType =
| {
stripTags?: boolean
}
| undefined
| null
export function normalizeData(
data: string | null,
config?: NormalizeConfigType
): string {
if (config?.stripTags) {
data = striptags(data as string)
}
return data as string
}