diff --git a/apps/seller/src/entity/products/create/create-delivery/index.ts b/apps/seller/src/entity/products/create/create-delivery/index.ts new file mode 100644 index 00000000..15986c05 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-delivery/index.ts @@ -0,0 +1,2 @@ +export { DeliveryCompany } from './product-delivery-company' +export { DeliveryTerms } from './product-delivery-terms' diff --git a/apps/seller/src/entity/products/create/create-disclosure/index.ts b/apps/seller/src/entity/products/create/create-disclosure/index.ts new file mode 100644 index 00000000..d3731691 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-disclosure/index.ts @@ -0,0 +1,2 @@ +export { DISCLOSURE_FIELDS, RADIO_OPTIONS } from './product-disclosure.constant' +export type { ProductInfoNoticeKey } from './product-disclosure.constant' diff --git a/apps/seller/src/entity/products/create/create-disclosure/product-disclosure.constant.ts b/apps/seller/src/entity/products/create/create-disclosure/product-disclosure.constant.ts index 70350c8e..fdcd07a9 100644 --- a/apps/seller/src/entity/products/create/create-disclosure/product-disclosure.constant.ts +++ b/apps/seller/src/entity/products/create/create-disclosure/product-disclosure.constant.ts @@ -5,17 +5,16 @@ export const DISCLOSURE_FIELDS = [ { label: '4. 소재지', key: 'originLocation' }, { label: '5. 제조년월일', key: 'manufactureDate' }, { label: '6. 소비기한 또는 품질 유지기한', key: 'expirationDate' }, - { label: '7. 보관방법', key: 'storageGuide' }, - { label: '8. 포장 단위 별 내용물 용량(중량) 수량', key: 'packagingContents' }, - { label: '9. 포장 단위별 수량', key: 'packagingQuantityUnit' }, + { label: '7. 포장 단위 별 내용물 용량(중량) 수량', key: 'packagingContents' }, + { label: '8. 포장 단위별 수량', key: 'packagingQuantityUnit' }, { - label: '10. 원재료명 (농수산물의 원산지 표시 등에 관한 법률)', + label: '9. 원재료명 (농수산물의 원산지 표시 등에 관한 법률)', key: 'rawMaterialName', }, - { label: '11. 영양성분', key: 'nutritionInfo' }, - { label: '12. 유전자 변형 식품에 해당하는 경우의 표시', key: 'transgenic' }, - { label: '13. 소비자 안전을 위한 주의사항', key: 'customerWarning' }, - { label: '14. 수입 식품의 경우', key: 'importFood' }, + { label: '10. 영양성분', key: 'nutritionInfo' }, + { label: '11. 유전자 변형 식품에 해당하는 경우의 표시', key: 'transgenic' }, + { label: '12. 소비자 안전을 위한 주의사항', key: 'customerWarning' }, + { label: '13. 수입 식품의 경우', key: 'importFood' }, ] as const export const RADIO_OPTIONS = [ diff --git a/apps/seller/src/entity/products/create/create-form/create-form.types.ts b/apps/seller/src/entity/products/create/create-form/create-form.types.ts new file mode 100644 index 00000000..2231a3c1 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-form/create-form.types.ts @@ -0,0 +1,13 @@ +import { + DeliveryFormInput, + ProductDisclosureFormInput, + ProductFormInput, + ProductOptionFormInput, + ThumbnailFormInput, +} from './create-indivisual-form.type' + +export type CreateFormType = ProductFormInput & + DeliveryFormInput & { + options: ProductOptionFormInput[] // Feature의 스키마 대신 Entity의 순수 타입을 사용 + } & ProductDisclosureFormInput & + ThumbnailFormInput diff --git a/apps/seller/src/entity/products/create/create-form/product-form.type.ts b/apps/seller/src/entity/products/create/create-form/create-indivisual-form.type.ts similarity index 86% rename from apps/seller/src/entity/products/create/create-form/product-form.type.ts rename to apps/seller/src/entity/products/create/create-form/create-indivisual-form.type.ts index a7e102bb..cd93376d 100644 --- a/apps/seller/src/entity/products/create/create-form/product-form.type.ts +++ b/apps/seller/src/entity/products/create/create-form/create-indivisual-form.type.ts @@ -6,7 +6,7 @@ export type ProductFormInput = { productionTime: string price: number | null discountAmount: number | null - discountType: 'won' | 'percentage' + discountType: 'AMOUNT' | 'RATE' } export type DeliveryFormInput = { @@ -16,8 +16,13 @@ export type DeliveryFormInput = { deliveryMinFee: number | null } +export type ThumbnailFormInput = { + mainImage: File | null + extraImages: File[] +} + export type ProductOptionFormInput = { - mainCategory: string + mainCategory: 'bread' | 'snack' | '' subCategory: string optionName: string ingredientCategories: ('glutenFree' | 'vegan')[] diff --git a/apps/seller/src/entity/products/create/create-form/create.api.ts b/apps/seller/src/entity/products/create/create-form/create.api.ts new file mode 100644 index 00000000..04077400 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-form/create.api.ts @@ -0,0 +1,21 @@ +import { client } from '@/shared/utils/axios' + +import { ApiResponse, StoreInfo } from './create.type' + +// storeId 조회 +export const getMyStore = async () => { + const response = await client.get>( + '/api/v1/seller/stores', + ) + return response.data.result.store +} + +// 상품 등록 +export const createProduct = async (formData: FormData) => { + const response = await client.post('/api/v1/seller/boards', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) + return response.data +} diff --git a/apps/seller/src/entity/products/create/create-form/create.query.ts b/apps/seller/src/entity/products/create/create-form/create.query.ts new file mode 100644 index 00000000..4e86afcf --- /dev/null +++ b/apps/seller/src/entity/products/create/create-form/create.query.ts @@ -0,0 +1,16 @@ +import { queryOptions } from '@tanstack/react-query' + +import { getMyStore } from './create.api' + +export const productKeys = { + all: ['products'] as const, + myStore: () => [...productKeys.all, 'myStore'] as const, +} + +export const productQueries = { + myStore: () => + queryOptions({ + queryKey: productKeys.myStore(), + queryFn: getMyStore, + }), +} diff --git a/apps/seller/src/entity/products/create/create-form/create.type.ts b/apps/seller/src/entity/products/create/create-form/create.type.ts new file mode 100644 index 00000000..882f0f84 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-form/create.type.ts @@ -0,0 +1,66 @@ +// API 요청 타입 +export interface CreateProductRequest { + storeId: number + title: string + isFresh: boolean + productionStartAt: string + price: number + discountType: 'AMOUNT' | 'RATE' + discountValue: number + deliveryCondition: string + deliveryCompany: string + deliveryFee: number + freeShippingConditions: number + content: string + products: ProductOptionRequest[] + productInfoNoticeRequest: Record +} + +export interface ProductOptionRequest { + title: string + category: string + plusPriceWithBoardPrice: number + stock: number + dietaryTags: { + glutenFreeTag: boolean + highProteinTag: boolean + sugarFreeTag: boolean + veganTag: boolean + ketogenicTag: boolean + } + availability: { + monday: boolean + tuesday: boolean + wednesday: boolean + thursday: boolean + friday: boolean + saturday: boolean + sunday: boolean + } + nutritionInfo: { + totalWeight: number + servingSize: number + carbohydrates: number + sugars: number + protein: number + fat: number + calories: number + } | null +} + +// API 응답 타입 +export interface StoreInfo { + storeId: number + name: string + introduce: string + profile: string + phoneNumber: string + email: string +} + +export interface ApiResponse { + success: boolean + code: number + message: string + result: T +} diff --git a/apps/seller/src/entity/products/create/create-form/index.ts b/apps/seller/src/entity/products/create/create-form/index.ts new file mode 100644 index 00000000..72a70819 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-form/index.ts @@ -0,0 +1,16 @@ +export type { CreateFormType } from './create-form.types' +export type { + ProductFormInput, + DeliveryFormInput, + ThumbnailFormInput, + ProductOptionFormInput, + ProductDisclosureFormInput, +} from './create-indivisual-form.type' +export { getMyStore, createProduct } from './create.api' +export { productQueries, productKeys } from './create.query' +export type { + CreateProductRequest, + ProductOptionRequest, + StoreInfo, + ApiResponse, +} from './create.type' diff --git a/apps/seller/src/entity/products/create/create-header/index.ts b/apps/seller/src/entity/products/create/create-header/index.ts new file mode 100644 index 00000000..af7a350e --- /dev/null +++ b/apps/seller/src/entity/products/create/create-header/index.ts @@ -0,0 +1,3 @@ +export { CategoryOptions } from './category-options.constants' +export { EssentialOptions } from './essential-options.constants' +export type { OptionTags } from './options-tag.type' diff --git a/apps/seller/src/entity/products/create/create-info/index.ts b/apps/seller/src/entity/products/create/create-info/index.ts new file mode 100644 index 00000000..49ba22de --- /dev/null +++ b/apps/seller/src/entity/products/create/create-info/index.ts @@ -0,0 +1,2 @@ +export { ProductDiscountType } from './product-discount-type.constants' +export { productionTimes } from './production-time.constants' diff --git a/apps/seller/src/entity/products/create/create-info/product-discount-type.constants.ts b/apps/seller/src/entity/products/create/create-info/product-discount-type.constants.ts index 641e95ea..114de0a0 100644 --- a/apps/seller/src/entity/products/create/create-info/product-discount-type.constants.ts +++ b/apps/seller/src/entity/products/create/create-info/product-discount-type.constants.ts @@ -1,10 +1,10 @@ export const ProductDiscountType = [ { label: '원', - value: 'won', + value: 'AMOUNT', }, { label: '%', - value: 'percentage', + value: 'RATE', }, ] diff --git a/apps/seller/src/entity/products/create/create-info/production-time.constants.ts b/apps/seller/src/entity/products/create/create-info/production-time.constants.ts index 578e37c8..f8fa2766 100644 --- a/apps/seller/src/entity/products/create/create-info/production-time.constants.ts +++ b/apps/seller/src/entity/products/create/create-info/production-time.constants.ts @@ -1,22 +1,7 @@ export const productionTimes = [ - { - label: '03:00~04:00', - value: '03:00~04:00', - }, - { - label: '04:00~05:00', - value: '04:00~05:00', - }, - { - label: '05:00~06:00', - value: '05:00~06:00', - }, - { - label: '06:00~07:00', - value: '06:00~07:00', - }, - { - label: '07:00~08:00', - value: '07:00~08:00', - }, + { label: '03:00~04:00', value: '03:00' }, + { label: '04:00~05:00', value: '04:00' }, + { label: '05:00~06:00', value: '05:00' }, + { label: '06:00~07:00', value: '06:00' }, + { label: '07:00~08:00', value: '07:00' }, ] diff --git a/apps/seller/src/entity/products/create/create-options/index.ts b/apps/seller/src/entity/products/create/create-options/index.ts new file mode 100644 index 00000000..ce4e42e0 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-options/index.ts @@ -0,0 +1,7 @@ +export { NUTRITION_FIELDS } from './product-nutritions.constant' +export type { NutritionFieldKey } from './product-nutritions.constant' +export { + MAIN_CATEGORY_OPTIONS, + SUB_CATEGORY_MAP, +} from './product-options.constant' +export { SHIPPING_DAYS } from './product-shipping-days.constant' diff --git a/apps/seller/src/entity/products/create/create-store/create-store-header.type.ts b/apps/seller/src/entity/products/create/create-store/create-store-header.type.ts new file mode 100644 index 00000000..8be8d920 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-store/create-store-header.type.ts @@ -0,0 +1,32 @@ +export type ProductFileType = Record + +export interface NutritionData { + sugar: number | null + protein: number | null + fat: number | null + ingredientCategories: string[] +} + +export interface ActiveTags { + [key: string]: boolean +} + +export interface CreateFormHeaderType { + productFields: ProductFileType + currentStep: number + headerHeight: number + + setProductFields: React.Dispatch> + setCurrentStep: React.Dispatch> + setHeaderHeight: React.Dispatch> + scrollToStep: (index: number) => void + + isScrollingToStep: React.MutableRefObject + + nutritionDataList: NutritionData[] + setNutritionData: (index: number, data: NutritionData) => void + activeTags: ActiveTags + + productPrice: number | null + setProductPrice: React.Dispatch> +} diff --git a/apps/seller/src/entity/products/create/create-store/index.ts b/apps/seller/src/entity/products/create/create-store/index.ts new file mode 100644 index 00000000..0749e913 --- /dev/null +++ b/apps/seller/src/entity/products/create/create-store/index.ts @@ -0,0 +1,5 @@ +export type { + NutritionData, + ActiveTags, + CreateFormHeaderType, +} from './create-store-header.type' diff --git a/apps/seller/src/entity/products/index.ts b/apps/seller/src/entity/products/index.ts index 6644c541..802396df 100644 --- a/apps/seller/src/entity/products/index.ts +++ b/apps/seller/src/entity/products/index.ts @@ -6,7 +6,11 @@ export * from './create/create-delivery/product-delivery-terms' export * from './create/create-disclosure/product-disclosure.constant' // Create - Form Types -export * from './create/create-form/product-form.type' +export * from './create/create-form/create-form.types' +export * from './create/create-form/create-indivisual-form.type' +export * from './create/create-form/create.api' +export * from './create/create-form/create.query' +export * from './create/create-form/create.type' // Create - Header export * from './create/create-header/category-options.constants' @@ -21,3 +25,6 @@ export * from './create/create-info/production-time.constants' export * from './create/create-options/product-nutritions.constant' export * from './create/create-options/product-options.constant' export * from './create/create-options/product-shipping-days.constant' + +// Create - store +export * from './create/create-store/create-store-header.type'