Skip to content
Merged

up #21

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,23 @@
"typescript": "5.9.2",
},
},
"packages/config": {
"name": "@qco/config",
"version": "0.0.0",
"dependencies": {
"@t3-oss/env-core": "0.13.8",
"zod": "4.0.16",
},
"devDependencies": {
"@qco/eslint-config": "workspace:*",
"@qco/prettier-config": "workspace:*",
"@qco/tsconfig": "workspace:*",
"eslint": "9.32.0",
"prettier": "3.6.2",
"tsup": "8.5.0",
"typescript": "5.9.2",
},
},
"packages/db": {
"name": "@qco/db",
"version": "0.1.0",
Expand Down Expand Up @@ -283,10 +300,10 @@
"name": "@qco/emails",
"version": "1.0.0",
"dependencies": {
"@qco/config": "workspace:*",
"@qco/tsconfig": "workspace:*",
"@radix-ui/colors": "3.0.0",
"@react-email/components": "0.5.0",
"@t3-oss/env-core": "0.13.8",
"@tailwindcss/typography": "0.5.16",
"nodemailer": "^7.0.5",
"react": "19.1.1",
Expand All @@ -296,7 +313,6 @@
"sharp": "^0.34.3",
"tailwindcss": "4.1.11",
"tailwindcss-animate": "1.0.7",
"zod": "4.0.16",
},
"devDependencies": {
"@react-email/preview-server": "4.2.8",
Expand Down Expand Up @@ -420,6 +436,7 @@
"name": "@qco/web-api",
"version": "0.1.0",
"dependencies": {
"@qco/config": "workspace:*",
"@qco/db": "workspace:*",
"@qco/lib": "workspace:*",
"@qco/web-validators": "workspace:*",
Expand Down Expand Up @@ -1118,6 +1135,8 @@

"@qco/auth": ["@qco/auth@workspace:packages/auth"],

"@qco/config": ["@qco/config@workspace:packages/config"],

"@qco/db": ["@qco/db@workspace:packages/db"],

"@qco/emails": ["@qco/emails@workspace:packages/emails"],
Expand Down
5 changes: 2 additions & 3 deletions docs/checkout-drafts-anonymous-users.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,8 @@ function CheckoutForm() {
setSessionId(null);
};

// Получение прогресса и ошибок
const progress = validation?.completeness ? getProgressMessage(validation.completeness) : "";
const groupedErrors = validation?.validation?.errors ? groupValidationErrors(validation.validation.errors) : {};
// Получение ошибок
const groupedErrors = validation?.data?.errors ? groupValidationErrors(validation.data.errors) : {};

return (
<div>
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/checkout-draft-usage-updated.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,9 @@ export function CheckoutForm() {
});

// Получение прогресса и ошибок
const progressMessage = completeness ? getProgressMessage(completeness) : "";
const groupedErrors = validation?.validation?.errors ?
groupValidationErrors(validation.validation.errors) : {};
const progressMessage = "";
const groupedErrors = validation?.data?.errors ?
groupValidationErrors(validation.data.errors) : {};

if (isDraftLoading) {
return <div>Загрузка сохраненных данных...</div>;
Expand Down
24 changes: 18 additions & 6 deletions packages/api/src/router/orders/create.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { eq } from "@qco/db";

import { orders, orderItems, customers } from "@qco/db/schema";
import { orders, orderItems, customers, PaymentMethod, PaymentStatus, ShippingMethod } from "@qco/db/schema";
import { protectedProcedure } from "../../trpc";
import { orderCreateSchema } from "@qco/validators";

Expand All @@ -26,13 +26,25 @@ export const create = protectedProcedure
const orderNumber = `ORD-${Date.now()}`;

// Create order
const [order] = await ctx.db.insert(orders).values({
const values: typeof orders.$inferInsert = {
customerId,
orderNumber,
status: "pending",
paymentStatus: orderData.paymentStatus || "PENDING",
...orderData,
}).returning();
subtotalAmount: orderData.subtotalAmount,
shippingAmount: orderData.shippingAmount,
discountAmount: orderData.discountAmount,
taxAmount: orderData.taxAmount,
totalAmount: orderData.totalAmount,
paymentMethod: orderData.paymentMethod as typeof PaymentMethod[keyof typeof PaymentMethod] | undefined,
shippingMethod: orderData.shippingMethod as typeof ShippingMethod[keyof typeof ShippingMethod] | undefined,
shippingAddressId: orderData.shippingAddressId ?? undefined,
notes: orderData.notes ?? undefined,
trackingNumber: orderData.trackingNumber ?? undefined,
metadata: orderData.metadata as typeof orders.$inferInsert["metadata"],
paymentStatus: orderData.paymentStatus as typeof PaymentStatus[keyof typeof PaymentStatus] | undefined,
};

const [order] = await ctx.db.insert(orders).values(values).returning();

if (!order) {
throw new TRPCError({
Expand Down
10 changes: 5 additions & 5 deletions packages/api/src/router/orders/get-by-customer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TRPCError } from "@trpc/server";
import { eq, and } from "drizzle-orm";
import { eq, and } from "@qco/db";

import { orders, customers } from "@qco/db/schema";
import { orders, customers, OrderStatus } from "@qco/db/schema";
import { protectedProcedure } from "../../trpc";
import { getOrdersByCustomerSchema, getOrdersByCustomerOutputSchema } from "@qco/validators";

Expand All @@ -26,7 +26,7 @@ export const getByCustomer = protectedProcedure
// Build where conditions
const whereConditions = [eq(orders.customerId, customerId)];
if (status) {
whereConditions.push(eq(orders.status, status));
whereConditions.push(eq(orders.status, status as typeof OrderStatus[keyof typeof OrderStatus]));
}

// Get orders
Expand All @@ -50,10 +50,10 @@ export const getByCustomer = protectedProcedure
id: order.id,
orderNumber: order.orderNumber,
status: order.status,
totalAmount: order.totalAmount,
totalAmount: String(order.totalAmount),
createdAt: order.createdAt.toISOString(),
updatedAt: order.updatedAt.toISOString(),
cancelledAt: order.cancelledAt?.toISOString() || null,
cancelledAt: order.cancelledAt ? order.cancelledAt.toISOString() : null,
})),
total: totalCount.length,
hasMore: totalCount.length > page * limit,
Expand Down
8 changes: 4 additions & 4 deletions packages/api/src/router/orders/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ async function getVariantOptions(

// Форматируем опции варианта
const variantOptions = optionCombinations
.filter(combination => combination.option && combination.optionValue)
.map(combination => ({
.filter((combination: any) => combination.option && combination.optionValue)
.map((combination: any) => ({
name: combination.option!.name,
value: combination.optionValue!.displayName || combination.optionValue!.value,
slug: combination.option!.slug,
Expand Down Expand Up @@ -140,9 +140,9 @@ export const list = publicProcedure
}

// Трансформируем данные для соответствия валидатору
return await Promise.all(data.map(async (order) => ({
return await Promise.all(data.map(async (order: any) => ({
...order,
items: await Promise.all(order.items?.map(async (item) => {
items: await Promise.all(order.items?.map(async (item: any) => {
const variant = item.variantId ? variantsMap[item.variantId] : null;

// Получаем опции варианта товара
Expand Down
28 changes: 22 additions & 6 deletions packages/api/src/router/product-attribute-values/upsert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { TRPCError } from "@trpc/server";
import { protectedProcedure } from "../../trpc";
import { productAttributeValues, productTypeAttributes } from "@qco/db/schema";
import { eq, and } from "@qco/db";
import { upsertProductAttributeValueSchema } from "@qco/validators";
import { upsertProductAttributeValueSchema, productAttributeValueSchema } from "@qco/validators";

export const upsert = protectedProcedure
.input(upsertProductAttributeValueSchema)
.output(productAttributeValueSchema)
.mutation(async ({ ctx, input }) => {
const { productId, attributeId, value } = input;

Expand All @@ -30,30 +31,45 @@ export const upsert = protectedProcedure
),
});

let result: typeof productAttributeValues.$inferSelect;
if (existingValue) {
// Обновляем существующее значение
[result] = await ctx.db
const rows = await ctx.db
.update(productAttributeValues)
.set({
value,
updatedAt: new Date(),
})
.where(eq(productAttributeValues.id, existingValue.id))
.returning();

if (!rows.length || !rows[0]) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to update product attribute value",
});
}

return rows[0];
} else {
// Создаем новое значение
[result] = await ctx.db
const rows = await ctx.db
.insert(productAttributeValues)
.values({
productId,
attributeId,
value,
})
.returning();
}

return result;
if (!rows.length || !rows[0]) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to insert product attribute value",
});
}

return rows[0];
}
} catch (error) {
if (error instanceof TRPCError) {
throw error;
Expand Down
2 changes: 0 additions & 2 deletions packages/auth/env.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { vercel } from "@t3-oss/env-nextjs/presets-zod";
import { z } from "zod";

export const env = createEnv({
extends: [vercel()],
server: {
AUTH_GOOGLE_CLIENT_ID: z.string().optional(),
AUTH_GOOGLE_CLIENT_SECRET: z.string().optional(),
Expand Down
42 changes: 42 additions & 0 deletions packages/config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "@qco/config",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": ["dist"],
"sideEffects": false,
"scripts": {
"build": "tsup",
"build:watch": "tsup --watch",
"clean": "git clean -xdf .cache .turbo dist node_modules",
"dev": "tsc -w",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"typecheck": "tsc --noEmit --emitDeclarationOnly false",
"prepare": "tsup"
},
"dependencies": {
"@t3-oss/env-core": "0.13.8",
"zod": "4.0.16"
},
"devDependencies": {
"@qco/eslint-config": "workspace:*",
"@qco/prettier-config": "workspace:*",
"@qco/tsconfig": "workspace:*",
"eslint": "9.32.0",
"prettier": "3.6.2",
"tsup": "8.5.0",
"typescript": "5.9.2"
},
"prettier": "@qco/prettier-config"
}


29 changes: 29 additions & 0 deletions packages/config/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";

export const env = createEnv({
server: {
NODE_ENV: z.enum(["development", "production", "test"]).optional(),
RESEND_API_KEY: z.string().optional(),
EMAIL_SANDBOX_ENABLED: z.coerce.boolean().optional().default(false),
EMAIL_SANDBOX_HOST: z.string().optional(),
EMAIL_FROM: z.string().email().optional(),
SITE_NAME: z.string().default("QCO"),
SITE_URL: z.string().url().optional(),
},
client: {},
clientPrefix: "NEXT_PUBLIC_",
runtimeEnv: {
NODE_ENV: process.env.NODE_ENV,
RESEND_API_KEY: process.env.RESEND_API_KEY,
EMAIL_SANDBOX_ENABLED: process.env.EMAIL_SANDBOX_ENABLED === "true",
EMAIL_SANDBOX_HOST: process.env.EMAIL_SANDBOX_HOST,
EMAIL_FROM: process.env.EMAIL_FROM,
SITE_NAME: process.env.SITE_NAME,
SITE_URL: process.env.SITE_URL,
},
skipValidation:
!!process.env.CI || process.env.npm_lifecycle_event === "lint",
});


3 changes: 3 additions & 0 deletions packages/config/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { env } from "./env";


7 changes: 7 additions & 0 deletions packages/config/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "@qco/tsconfig/internal-package.json",
"include": ["src"],
"exclude": ["node_modules"]
}


17 changes: 17 additions & 0 deletions packages/config/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { defineConfig } from "tsup";

export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
dts: true,
splitting: false,
sourcemap: false,
clean: true,
minify: false,
external: [
"@t3-oss/env-core",
"zod"
],
});


2 changes: 1 addition & 1 deletion packages/emails/emails/admin-invitation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "@react-email/components";

import { emailTailwindConfig } from "../tailwind";
import { env } from "../env";
import { env } from "@qco/config";

interface AdminInvitationEmailProps {
name: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/emails/emails/auth/email-change-verification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "@react-email/components";

import { emailTailwindConfig } from "../../tailwind";
import { env } from "../../env";
import { env } from "@qco/config";

export default function EmailChangeVerification({ otp }: { otp: string }) {
return (
Expand Down
2 changes: 1 addition & 1 deletion packages/emails/emails/auth/email-verification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "@react-email/components";

import { emailTailwindConfig } from "../../tailwind";
import { env } from "../../env";
import { env } from "@qco/config";

interface EmailVerificationProps {
otp: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/emails/emails/auth/otp-sign-in.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "@react-email/components";

import { emailTailwindConfig } from "../../tailwind";
import { env } from "../../env";
import { env } from "@qco/config";

export default function OtpSignInEmail({
otp,
Expand Down
Loading
Loading