enh
This commit is contained in:
parent
db2ee44a5f
commit
6d67a1e759
9 changed files with 67 additions and 14 deletions
|
|
@ -44,6 +44,8 @@ export default function AddProduct() {
|
|||
images: variantUrls,
|
||||
isFlashAvailable: variant.isFlashAvailable || false,
|
||||
flashPrice: variant.flashPrice ? parseFloat(variant.flashPrice) : undefined,
|
||||
isOffer: variant.isOffer || false,
|
||||
isComboOnly: variant.isComboOnly || false,
|
||||
features: variant.attributes.map((attr: any) => ({
|
||||
featureName: attr.featureName,
|
||||
featureValue: attr.featureValue,
|
||||
|
|
@ -85,6 +87,8 @@ export default function AddProduct() {
|
|||
marketPrice: '',
|
||||
isFlashAvailable: false,
|
||||
flashPrice: '',
|
||||
isOffer: false,
|
||||
isComboOnly: false,
|
||||
attributes: [{ featureName: 'quantity', featureValue: '' }],
|
||||
comboItems: [] as { skuId: number | string }[],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ export default function EditProduct() {
|
|||
marketPrice: sku.marketPrice || '',
|
||||
isFlashAvailable: sku.isFlashAvailable || false,
|
||||
flashPrice: sku.flashPrice || '',
|
||||
isOffer: sku.isOffer || false,
|
||||
isComboOnly: sku.isComboOnly || false,
|
||||
attributes: (sku.features || []).map((f) => ({
|
||||
featureName: f.featureName,
|
||||
featureValue: f.featureValue,
|
||||
|
|
@ -118,6 +120,8 @@ export default function EditProduct() {
|
|||
images: allUrls,
|
||||
isFlashAvailable: variant.isFlashAvailable || false,
|
||||
flashPrice: variant.flashPrice ? parseFloat(variant.flashPrice) : undefined,
|
||||
isOffer: variant.isOffer || false,
|
||||
isComboOnly: variant.isComboOnly || false,
|
||||
features: variant.attributes.map((attr: any) => ({
|
||||
featureName: attr.featureName,
|
||||
featureValue: attr.featureValue,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import MaterialIcons from '@expo/vector-icons/MaterialIcons'
|
|||
import { trpc } from '../trpc-client'
|
||||
|
||||
interface Attribute {
|
||||
featureName: string
|
||||
featureName: string | null
|
||||
featureValue: string
|
||||
}
|
||||
|
||||
|
|
@ -17,6 +17,8 @@ interface Variant {
|
|||
marketPrice: string
|
||||
isFlashAvailable: boolean
|
||||
flashPrice: string
|
||||
isOffer: boolean
|
||||
isComboOnly: boolean
|
||||
attributes: Attribute[]
|
||||
comboItems: { skuId: number | string }[]
|
||||
}
|
||||
|
|
@ -52,6 +54,8 @@ const defaultVariant = (): Variant => ({
|
|||
marketPrice: '',
|
||||
isFlashAvailable: false,
|
||||
flashPrice: '',
|
||||
isOffer: false,
|
||||
isComboOnly: false,
|
||||
attributes: [defaultAttribute()],
|
||||
comboItems: [],
|
||||
})
|
||||
|
|
@ -210,7 +214,7 @@ const ProductForm = forwardRef<ProductFormRef, ProductFormProps>(({
|
|||
<View style={tw`flex-1`}>
|
||||
<MyTextInput
|
||||
placeholder="Name"
|
||||
value={attr.featureName}
|
||||
value={attr.featureName ?? ''}
|
||||
onChangeText={handleChange(`variants.${vIndex}.attributes.${aIndex}.featureName`)}
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -265,6 +269,24 @@ const ProductForm = forwardRef<ProductFormRef, ProductFormProps>(({
|
|||
<MyText style={tw`text-gray-700 font-medium`}>Flash Available</MyText>
|
||||
</View>
|
||||
|
||||
<View style={tw`flex-row items-center mb-3`}>
|
||||
<Checkbox
|
||||
checked={variant.isOffer}
|
||||
onPress={() => setFieldValue(`variants.${vIndex}.isOffer`, !variant.isOffer)}
|
||||
style={tw`mr-3`}
|
||||
/>
|
||||
<MyText style={tw`text-gray-700 font-medium`}>Offer SKU</MyText>
|
||||
</View>
|
||||
|
||||
<View style={tw`flex-row items-center mb-3`}>
|
||||
<Checkbox
|
||||
checked={variant.isComboOnly}
|
||||
onPress={() => setFieldValue(`variants.${vIndex}.isComboOnly`, !variant.isComboOnly)}
|
||||
style={tw`mr-3`}
|
||||
/>
|
||||
<MyText style={tw`text-gray-700 font-medium`}>Combo Only SKU</MyText>
|
||||
</View>
|
||||
|
||||
{variant.isFlashAvailable && (
|
||||
<MyTextInput
|
||||
topLabel="Flash Price"
|
||||
|
|
|
|||
|
|
@ -196,8 +196,10 @@ export const productRouter = router({
|
|||
images: z.array(z.string()).optional().default([]),
|
||||
isFlashAvailable: z.boolean().optional().default(false),
|
||||
flashPrice: z.number().optional().nullable(),
|
||||
isOffer: z.boolean().optional().default(false),
|
||||
isComboOnly: z.boolean().optional().default(false),
|
||||
features: z.array(z.object({
|
||||
featureName: z.string().min(1, 'Attribute name is required'),
|
||||
featureName: z.string().nullable().optional(),
|
||||
featureValue: z.string().min(1, 'Value is required'),
|
||||
})).min(1, 'At least one feature is required'),
|
||||
comboItems: z.array(z.object({
|
||||
|
|
@ -222,8 +224,10 @@ export const productRouter = router({
|
|||
images: sku.images.map((url) => extractKeyFromPresignedUrl(url)),
|
||||
isFlashAvailable: sku.isFlashAvailable,
|
||||
flashPrice: sku.flashPrice ?? null,
|
||||
isOffer: sku.isOffer,
|
||||
isComboOnly: sku.isComboOnly,
|
||||
features: sku.features.map((f) => ({
|
||||
featureName: f.featureName,
|
||||
featureName: f.featureName?.trim() || null,
|
||||
featureValue: f.featureValue,
|
||||
})),
|
||||
comboItems: (sku.comboItems || []).map((ci) => ({ skuId: ci.skuId })),
|
||||
|
|
@ -278,8 +282,10 @@ export const productRouter = router({
|
|||
images: z.array(z.string()).optional().default([]),
|
||||
isFlashAvailable: z.boolean().optional().default(false),
|
||||
flashPrice: z.number().optional().nullable(),
|
||||
isOffer: z.boolean().optional().default(false),
|
||||
isComboOnly: z.boolean().optional().default(false),
|
||||
features: z.array(z.object({
|
||||
featureName: z.string().min(1, 'Attribute name is required'),
|
||||
featureName: z.string().nullable().optional(),
|
||||
featureValue: z.string().min(1, 'Value is required'),
|
||||
})).min(1, 'At least one feature is required'),
|
||||
comboItems: z.array(z.object({
|
||||
|
|
@ -306,8 +312,10 @@ export const productRouter = router({
|
|||
images: sku.images.map((url) => extractKeyFromPresignedUrl(url)),
|
||||
isFlashAvailable: sku.isFlashAvailable,
|
||||
flashPrice: sku.flashPrice ?? null,
|
||||
isOffer: sku.isOffer,
|
||||
isComboOnly: sku.isComboOnly,
|
||||
features: sku.features.map((f) => ({
|
||||
featureName: f.featureName,
|
||||
featureName: f.featureName?.trim() || null,
|
||||
featureValue: f.featureValue,
|
||||
})),
|
||||
comboItems: (sku.comboItems || []).map((ci) => ({ skuId: ci.skuId })),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ CREATE TABLE `product_skus` (
|
|||
`is_suspended` integer DEFAULT false NOT NULL,
|
||||
`is_flash_available` integer DEFAULT false NOT NULL,
|
||||
`flash_price` text,
|
||||
`is_offer` integer DEFAULT false NOT NULL,
|
||||
`is_combo_only` integer DEFAULT false NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`product_id`) REFERENCES `product_info`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
|
|
@ -23,7 +25,7 @@ CREATE TABLE `product_skus` (
|
|||
CREATE TABLE `sku_features` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`sku_id` integer NOT NULL,
|
||||
`feature_name` text NOT NULL,
|
||||
`feature_name` text,
|
||||
`feature_value` text NOT NULL,
|
||||
FOREIGN KEY (`sku_id`) REFERENCES `product_skus`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ const mapSku = (sku: SkuRow, features: SkuFeatureRow[] = [], comboItems: any[] =
|
|||
isSuspended: sku.isSuspended,
|
||||
isFlashAvailable: sku.isFlashAvailable,
|
||||
flashPrice: sku.flashPrice ? String(sku.flashPrice) : null,
|
||||
isOffer: sku.isOffer,
|
||||
isComboOnly: sku.isComboOnly,
|
||||
createdAt: sku.createdAt,
|
||||
features: features.map(mapSkuFeature),
|
||||
comboItems: comboItems,
|
||||
|
|
@ -275,6 +277,8 @@ export async function createProduct(input: CreateProductInput): Promise<AdminPro
|
|||
images: sku.images ?? null,
|
||||
isFlashAvailable: sku.isFlashAvailable ?? false,
|
||||
flashPrice: sku.flashPrice != null ? String(sku.flashPrice) : null,
|
||||
isOffer: sku.isOffer ?? false,
|
||||
isComboOnly: sku.isComboOnly ?? false,
|
||||
}))
|
||||
).returning()
|
||||
|
||||
|
|
@ -362,6 +366,8 @@ export async function updateProduct(id: number, input: any): Promise<AdminProduc
|
|||
images: sku.images ?? null,
|
||||
isFlashAvailable: sku.isFlashAvailable ?? false,
|
||||
flashPrice: sku.flashPrice != null ? String(sku.flashPrice) : null,
|
||||
isOffer: sku.isOffer ?? false,
|
||||
isComboOnly: sku.isComboOnly ?? false,
|
||||
})
|
||||
.where(eq(productSkus.id, sku.id))
|
||||
|
||||
|
|
@ -393,6 +399,8 @@ export async function updateProduct(id: number, input: any): Promise<AdminProduc
|
|||
images: sku.images ?? null,
|
||||
isFlashAvailable: sku.isFlashAvailable ?? false,
|
||||
flashPrice: sku.flashPrice != null ? String(sku.flashPrice) : null,
|
||||
isOffer: sku.isOffer ?? false,
|
||||
isComboOnly: sku.isComboOnly ?? false,
|
||||
}).returning()
|
||||
|
||||
await db.insert(skuFeatures).values(
|
||||
|
|
|
|||
|
|
@ -208,13 +208,15 @@ export const productSkus = sqliteTable('product_skus', {
|
|||
isSuspended: integer('is_suspended', { mode: 'boolean' }).notNull().default(false),
|
||||
isFlashAvailable: integer('is_flash_available', { mode: 'boolean' }).notNull().default(false),
|
||||
flashPrice: numericText('flash_price'),
|
||||
isOffer: integer('is_offer', { mode: 'boolean' }).notNull().default(false),
|
||||
isComboOnly: integer('is_combo_only', { mode: 'boolean' }).notNull().default(false),
|
||||
createdAt: timestampText('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
|
||||
})
|
||||
|
||||
export const skuFeatures = sqliteTable('sku_features', {
|
||||
id: integer().primaryKey({ autoIncrement: true }),
|
||||
skuId: integer('sku_id').notNull().references(() => productSkus.id),
|
||||
featureName: text('feature_name').notNull(),
|
||||
featureName: text('feature_name'),
|
||||
featureValue: text('feature_value').notNull(),
|
||||
}, (t) => ({
|
||||
unq_sku_feature_name: uniqueIndex('unique_sku_feature_name').on(t.skuId, t.featureName),
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ export interface ProductSummaryData {
|
|||
isOutOfStock: boolean
|
||||
unitShortNotation: string
|
||||
productQuantity: number
|
||||
features: { featureName: string; featureValue: string }[]
|
||||
features: { featureName: string | null; featureValue: string }[]
|
||||
}
|
||||
|
||||
export async function getAllProductsWithUnits(tagId?: number): Promise<ProductSummaryData[]> {
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ export interface AdminOrderDetailsItem {
|
|||
isPackaged: boolean;
|
||||
isPackageVerified: boolean;
|
||||
skuName?: string | null;
|
||||
features?: { featureName: string; featureValue: string }[];
|
||||
features?: { featureName: string | null; featureValue: string }[];
|
||||
}
|
||||
|
||||
export interface AdminOrderDetailsPayment {
|
||||
|
|
@ -251,7 +251,7 @@ export interface AdminSlotOrderItem {
|
|||
isPackaged: boolean;
|
||||
isPackageVerified: boolean;
|
||||
skuName?: string | null;
|
||||
features?: { featureName: string; featureValue: string }[];
|
||||
features?: { featureName: string | null; featureValue: string }[];
|
||||
}
|
||||
|
||||
export interface AdminSlotOrder {
|
||||
|
|
@ -292,7 +292,7 @@ export interface AdminOrderListItemProduct {
|
|||
isPackaged: boolean;
|
||||
isPackageVerified: boolean;
|
||||
skuName?: string | null;
|
||||
features?: { featureName: string; featureValue: string }[];
|
||||
features?: { featureName: string | null; featureValue: string }[];
|
||||
}
|
||||
|
||||
export interface AdminOrderListItem {
|
||||
|
|
@ -363,7 +363,7 @@ export interface AdminUnit {
|
|||
export interface AdminSkuFeature {
|
||||
id: number;
|
||||
skuId: number;
|
||||
featureName: string;
|
||||
featureName: string | null;
|
||||
featureValue: string;
|
||||
}
|
||||
|
||||
|
|
@ -388,6 +388,8 @@ export interface AdminSku {
|
|||
isSuspended: boolean
|
||||
isFlashAvailable: boolean
|
||||
flashPrice: string | null
|
||||
isOffer: boolean
|
||||
isComboOnly: boolean
|
||||
createdAt: Date
|
||||
features: AdminSkuFeature[]
|
||||
comboItems: AdminProductComboItem[]
|
||||
|
|
@ -429,6 +431,7 @@ export interface CreateSkuInput {
|
|||
isSuspended?: boolean
|
||||
isFlashAvailable?: boolean
|
||||
flashPrice?: number | string | null
|
||||
isOffer?: boolean
|
||||
isComboOnly?: boolean
|
||||
sortOrder?: number
|
||||
isDefault?: boolean
|
||||
|
|
@ -573,7 +576,7 @@ export interface AdminSlotProductSummary {
|
|||
name: string;
|
||||
images: string[] | null;
|
||||
skuName?: string | null;
|
||||
features?: { featureName: string; featureValue: string }[];
|
||||
features?: { featureName: string | null; featureValue: string }[];
|
||||
}
|
||||
|
||||
export interface AdminVendorSnippet {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue