diff --git a/apps/admin-ui/components/ProductListDialog.tsx b/apps/admin-ui/components/ProductListDialog.tsx index 03d5d3a..82b2cf0 100644 --- a/apps/admin-ui/components/ProductListDialog.tsx +++ b/apps/admin-ui/components/ProductListDialog.tsx @@ -1,11 +1,9 @@ import React from 'react'; import { View, ScrollView } from 'react-native'; import { BottomDialog, MyText, tw } from 'common-ui'; +import type { IdName } from '@packages/shared'; -interface VendorSnippetProduct { - id: number; - name: string; -} +type VendorSnippetProduct = IdName; interface ProductListDialogProps { open: boolean; diff --git a/apps/admin-ui/components/context/staff-auth-context.tsx b/apps/admin-ui/components/context/staff-auth-context.tsx index fc14804..1d25c08 100644 --- a/apps/admin-ui/components/context/staff-auth-context.tsx +++ b/apps/admin-ui/components/context/staff-auth-context.tsx @@ -5,11 +5,9 @@ import { DeviceEventEmitter } from "react-native"; import { FORCE_LOGOUT_EVENT } from "common-ui/src/lib/const-strs"; import { trpc } from "@/src/trpc-client"; import { saveJWT, getJWT, deleteJWT } from "@/hooks/useJWT"; +import type { IdName } from '@packages/shared'; -interface Staff { - id: number; - name: string; -} +type Staff = IdName; interface StaffAuthContextType { isLoggedIn: boolean; diff --git a/apps/admin-ui/src/components/TagForm.tsx b/apps/admin-ui/src/components/TagForm.tsx index 6e4e769..f54f77e 100644 --- a/apps/admin-ui/src/components/TagForm.tsx +++ b/apps/admin-ui/src/components/TagForm.tsx @@ -9,11 +9,9 @@ import DraggableFlatList, { ScaleDecorator } from 'react-native-draggable-flatli import { Image } from 'expo-image'; import ProductsSelector from '@/components/ProductsSelector'; import { trpc } from '@/src/trpc-client'; +import type { IdName } from '@packages/shared'; -interface StoreOption { - id: number; - name: string; -} +type StoreOption = IdName; interface TagFormData { tagName: string; diff --git a/apps/admin-ui/types/vendor-snippets.ts b/apps/admin-ui/types/vendor-snippets.ts index 0271492..6285c02 100644 --- a/apps/admin-ui/types/vendor-snippets.ts +++ b/apps/admin-ui/types/vendor-snippets.ts @@ -1,7 +1,6 @@ -export interface VendorSnippetProduct { - id: number; - name: string; -} +import type { IdName } from '@packages/shared'; + +export type VendorSnippetProduct = IdName; export interface VendorSnippet { id: number; diff --git a/apps/user-ui/app/(auth)/login.tsx b/apps/user-ui/app/(auth)/login.tsx index 46eccc9..972f64d 100644 --- a/apps/user-ui/app/(auth)/login.tsx +++ b/apps/user-ui/app/(auth)/login.tsx @@ -10,12 +10,7 @@ import { TermsAndConditionsContent } from "@/components/TermsAndConditions"; import { LinearGradient } from "expo-linear-gradient"; import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view"; import { SafeAreaView } from "react-native-safe-area-context"; - -interface LoginFormInputs { - mobile: string; - otp?: string; - password?: string; -} +import type { LoginFormInputs } from '@packages/shared'; function Login() { const { loginWithToken } = useAuth(); diff --git a/apps/user-ui/app/(drawer)/(tabs)/me/my-orders/index.tsx b/apps/user-ui/app/(drawer)/(tabs)/me/my-orders/index.tsx index 57f308e..85f0ea4 100755 --- a/apps/user-ui/app/(drawer)/(tabs)/me/my-orders/index.tsx +++ b/apps/user-ui/app/(drawer)/(tabs)/me/my-orders/index.tsx @@ -10,35 +10,8 @@ import { orderStatusManipulator } from '@/src/lib/string-manipulators'; import dayjs from 'dayjs'; import OrderMenu from '@/components/OrderMenu'; -// Type definitions -interface OrderItem { - productName: string; - quantity: number; - price: number; - amount: number; - image: string | null; -} - -interface Order { - id: number; - orderId: string; - orderDate: string; - deliveryStatus: string; - deliveryDate?: string; - orderStatus: string; - cancelReason: string | null; - totalAmount: number; - deliveryCharge: number; - paymentMode: string; - paymentStatus: string; - refundStatus: string; - refundAmount: number | null; - userNotes: string | null; - items: OrderItem[]; - discountAmount?: number; - isFlashDelivery: boolean; - createdAt: string; -} +// Type definitions (order view models live in @/src/types/orders) +import type { Order, OrderItem } from '@/src/types/orders'; interface OrderFooterProps { isLoadingMore: boolean; diff --git a/apps/user-ui/components/NextOrderGlimpse.tsx b/apps/user-ui/components/NextOrderGlimpse.tsx index 965e424..c122dff 100644 --- a/apps/user-ui/components/NextOrderGlimpse.tsx +++ b/apps/user-ui/components/NextOrderGlimpse.tsx @@ -10,40 +10,12 @@ import { Image } from 'expo-image'; import { orderStatusManipulator } from '@/src/lib/string-manipulators'; import { useGetEssentialConsts } from '@/src/hooks/prominent-api-hooks'; import { useUserDetails } from '@/src/contexts/AuthContext'; +import type { Order, OrderItem } from '@/src/types/orders'; const { width: screenWidth } = Dimensions.get('window'); const CARD_WIDTH = (screenWidth - 48) * 0.95; // card width (24px padding each side), reduced 5% const SNAP_INTERVAL = CARD_WIDTH + 24; // card + right margin = page width -interface OrderItem { - productName: string; - quantity: number; - price: number; - amount: number; - image: string | null; -} - -interface Order { - id: number; - orderId: string; - orderDate: string; - deliveryStatus: string; - deliveryDate?: string; - orderStatus: string; - cancelReason: string | null; - totalAmount: number; - deliveryCharge: number; - paymentMode: string; - paymentStatus: string; - refundStatus: string; - refundAmount: number | null; - userNotes: string | null; - items: OrderItem[]; - discountAmount?: number; - isFlashDelivery: boolean; - createdAt: string; -} - interface OrderCardProps { order: Order; onPress: () => void; diff --git a/apps/user-ui/hooks/useAuthenticatedRoute.ts b/apps/user-ui/hooks/useAuthenticatedRoute.ts index bb36c25..e90af7d 100644 --- a/apps/user-ui/hooks/useAuthenticatedRoute.ts +++ b/apps/user-ui/hooks/useAuthenticatedRoute.ts @@ -1,6 +1,7 @@ import { useFocusEffect } from '@react-navigation/native'; import { useRouter } from 'expo-router'; import { useAuth } from '@/src/contexts/AuthContext'; +import type { RedirectState } from '@/src/contexts/AuthContext'; import { StorageServiceCasual } from 'common-ui'; import constants from '@/src/constants'; @@ -9,12 +10,6 @@ interface AuthenticatedRouteOptions { queryParams?: Record; } -interface RedirectState { - targetUrl: string; - queryParams: Record; - timestamp: number; -} - export function useAuthenticatedRoute(options: AuthenticatedRouteOptions = {}) { const { isAuthenticated, isLoading } = useAuth(); const router = useRouter(); diff --git a/apps/user-ui/src/contexts/AuthContext.tsx b/apps/user-ui/src/contexts/AuthContext.tsx index 4b56add..cfd7b37 100644 --- a/apps/user-ui/src/contexts/AuthContext.tsx +++ b/apps/user-ui/src/contexts/AuthContext.tsx @@ -8,7 +8,7 @@ import { StorageServiceCasual } from 'common-ui'; import { useRouter } from 'expo-router'; import constants from '@/src/constants'; -interface RedirectState { +export interface RedirectState { targetUrl: string; queryParams: Record; timestamp: number; diff --git a/apps/user-ui/src/hooks/prominent-api-hooks.ts b/apps/user-ui/src/hooks/prominent-api-hooks.ts index 70b8367..3f078fb 100644 --- a/apps/user-ui/src/hooks/prominent-api-hooks.ts +++ b/apps/user-ui/src/hooks/prominent-api-hooks.ts @@ -56,7 +56,7 @@ type StoreWithProductsResponse = StoreWithProductsApiType; type AvailabilityResponse = AvailabilityApiType; type BaseProduct = AllProductsApiType['products'][number] -type AvailabilityEntry = AvailabilityApiType['availability'][number] +export type AvailabilityEntry = AvailabilityApiType['availability'][number] export type MergedProduct = BaseProduct & { price: number diff --git a/apps/user-ui/src/store/centralSlotStore.ts b/apps/user-ui/src/store/centralSlotStore.ts index 68fe06b..688e469 100644 --- a/apps/user-ui/src/store/centralSlotStore.ts +++ b/apps/user-ui/src/store/centralSlotStore.ts @@ -1,11 +1,11 @@ import { create } from 'zustand'; import { useSlots, useAvailability } from '@/src/hooks/prominent-api-hooks'; +import type { AvailabilityEntry } from '@/src/hooks/prominent-api-hooks'; import { useEffect } from 'react'; -import { SlotsApiType, AvailabilityApiType } from "@backend/trpc/router"; +import { SlotsApiType } from "@backend/trpc/router"; type Slot = SlotsApiType['slots'][number]; type ProductAvailability = SlotsApiType['productAvailability'][number]; -type AvailabilityEntry = AvailabilityApiType['availability'][number]; interface ProductSlotInfo { slots: Slot[]; diff --git a/apps/user-ui/src/types/auth.ts b/apps/user-ui/src/types/auth.ts index 7b92a0a..5f02fef 100644 --- a/apps/user-ui/src/types/auth.ts +++ b/apps/user-ui/src/types/auth.ts @@ -27,18 +27,12 @@ export interface AuthState { token: string | null; } -export interface LoginCredentials { - identifier: string; // email or mobile - password: string; -} +import type { LoginRequest, RegisterRequest } from '@packages/shared' -export interface RegisterData { - name: string; - email: string; - mobile: string; - password: string; - profileImageUrl?: string | null; -} +// Wire-contract shapes live in @packages/shared (inputs.types.ts) — +// these aliases preserve the local names used across user-ui. +export type LoginCredentials = LoginRequest +export type RegisterData = RegisterRequest export interface UpdateProfileData { name?: string; diff --git a/apps/user-ui/src/types/orders.ts b/apps/user-ui/src/types/orders.ts new file mode 100644 index 0000000..35f88f7 --- /dev/null +++ b/apps/user-ui/src/types/orders.ts @@ -0,0 +1,31 @@ +// Shared order view-model types for user-ui +// (Were identically duplicated in me/my-orders/index.tsx and NextOrderGlimpse.tsx) + +export interface OrderItem { + productName: string; + quantity: number; + price: number; + amount: number; + image: string | null; +} + +export interface Order { + id: number; + orderId: string; + orderDate: string; + deliveryStatus: string; + deliveryDate?: string; + orderStatus: string; + cancelReason: string | null; + totalAmount: number; + deliveryCharge: number; + paymentMode: string; + paymentStatus: string; + refundStatus: string; + refundAmount: number | null; + userNotes: string | null; + items: OrderItem[]; + discountAmount?: number; + isFlashDelivery: boolean; + createdAt: string; +} diff --git a/apps/web-ui/src/routes/login.tsx b/apps/web-ui/src/routes/login.tsx index e5b3fb2..3f42197 100644 --- a/apps/web-ui/src/routes/login.tsx +++ b/apps/web-ui/src/routes/login.tsx @@ -5,15 +5,10 @@ import { useAuth } from '../lib/auth-context' import { trpc } from '../lib/trpc-client' import { useGetEssentialConsts } from '../hooks/prominent-api-hooks' import { MyButton, pInput as PInput } from 'web-components' +import type { LoginFormInputs } from '@packages/shared' export const Route = createFileRoute('/login')({ component: LoginPage }) -interface LoginFormInputs { - mobile: string - otp?: string - password?: string -} - function LoginPage() { const { loginWithToken } = useAuth() const navigate = useNavigate() diff --git a/change-log.txt b/change-log.txt index d4a6c1c..d9c90a7 100644 --- a/change-log.txt +++ b/change-log.txt @@ -747,3 +747,110 @@ Context: user approved the db-helper-unification plan (SKU model canonical; post === REBUILT types_inventory.md (latest snapshot) === 792 types (521 unique), 143 duplicate names, 131 identical-property clusters, 711 `any` usages across 210 files. Organized by file + by name, duplicate clusters w/ consumers, identical-property clusters, per-file `any` table. + +[2026-09-04 23:36:11] PHASE 1: dedupe packages/shared/types/admin.ts — 10 types re-declared identically in dedicated files are replaced by re-exports (verified byte-identical modulo comments/whitespace). + +=== packages/shared/types/admin.ts === +- removed local declarations: Banner, Complaint, ComplaintWithUser, Constant, ConstantUpdateResult, Coupon, CouponValidationResult, UserMiniInfo, StaffUser, StaffRole +- added re-export block: + export type { Banner } from './banner.types' + export type { Complaint, ComplaintWithUser } from './complaint.types' + export type { Constant, ConstantUpdateResult } from './const.types' + export type { Coupon, CouponValidationResult, UserMiniInfo } from './coupon.types' + export type { StaffUser, StaffRole } from './staff-user.types' +- KEPT in admin.ts: Store (canonical home — store.types.ts note says so), AdminOrderRow and everything below + +[2026-09-04 23:40:00] PHASE 1b: packages/shared/types/user.ts — UserBanner is byte-identical to Banner; replaced local declaration with alias. +- removed local interface UserBanner (10 fields) at user.ts ~line 119 +- added: import type { Banner } from './banner.types' + export type UserBanner = Banner + (5 live consumers — sqlite/postgres banners.ts, backend dbService re-export — keep working unchanged) + +[2026-09-04 23:47:00] PHASE 2: centralize cross-app / in-app exact-duplicate types. + +=== apps/user-ui/src/types/auth.ts === +- replaced local interfaces with shared aliases (shared/inputs.types.ts LoginRequest/RegisterRequest verified byte-identical): + removed: export interface LoginCredentials { identifier: string; password: string; } + export interface RegisterData { name; email; mobile; password; profileImageUrl?: string | null; } + added: import type { LoginRequest, RegisterRequest } from '@packages/shared' + export type LoginCredentials = LoginRequest + export type RegisterData = RegisterRequest + (6 consumer files keep importing the same names from '@/src/types/auth' — zero consumer edits) + +=== apps/user-ui/hooks/useAuthenticatedRoute.ts + src/contexts/AuthContext.tsx === +- RedirectState identical in both. Canonical: AuthContext (line 11 interface → exported). +- hook: deleted local interface, added import type { RedirectState } from '@/src/contexts/AuthContext' + (hook already imports useAuth from AuthContext — no new cycle) + +=== login forms (user-ui + web-ui) === +- both LoginFormInputs identical. Canonical: shared/app-common.types.ts LoginFormInputs (already there). +- apps/user-ui/app/(auth)/login.tsx: deleted local interface, added import type { LoginFormInputs } from '@packages/shared' +- apps/web-ui/src/routes/login.tsx: deleted local interface, added import type { LoginFormInputs } from '@packages/shared' + +=== user-ui Order/OrderItem view models === +- new file apps/user-ui/src/types/orders.ts exporting the identical Order + OrderItem interfaces (from me/my-orders/index.tsx) +- me/my-orders/index.tsx + components/NextOrderGlimpse.tsx: deleted locals (incl. the '// Type definitions' comment), import from '@/src/types/orders' + +=== apps/user-ui/src/store/centralSlotStore.ts === +- deleted local type AvailabilityEntry = AvailabilityApiType['availability'][number] (line 8) +- added import type { AvailabilityEntry } from '@/src/hooks/prominent-api-hooks' + (type-only import — no runtime cycle with the store's existing value import from the same file) + +[2026-09-04 23:55:00] PHASE 3: centralize remaining exact-duplicate db types. + +(a) FIX broken seed re-export chain (prior session migrated lib/seed.ts to shared imports but left index.ts re-exporting from lib/seed): +- packages/db_helper_sqlite/src/lib/seed.ts + packages/db_helper_postgres/src/lib/seed.ts: added + export type { UnitSeedData, StaffRoleName, StaffPermissionName, RolePermissionAssignment, KeyValSeedData } from '@packages/shared' + (index.ts `export { ..., type UnitSeedData, ... } from './src/lib/seed'` blocks resolve again) + +(b) NEW packages/shared/types/order.types.ts: PlacedOrder, CouponUsageWithCoupon, GetAllOrdersInput + (copied verbatim from sqlite; pg verified byte-identical. NOT included: OrderWithCancellationData — extends drifted OrderWithFullData, stays local in both packages.) +- shared/types/index.ts: added export type * from './order.types'; + +(c) MIGRATIONS to shared: +- sqlite+pg user-apis/order.ts: deleted local PlacedOrder + CouponUsageWithCoupon; extended existing '@packages/shared' import +- sqlite+pg admin-apis/order.ts: deleted local GetAllOrdersInput; extended existing '@packages/shared' import +- sqlite+pg stores/store-helpers.ts: deleted local StoreBasicData interface; added + import type { StoreSummary } from '@packages/shared' + export type StoreBasicData = StoreSummary + (index.ts `type StoreBasicData` export lines + backend consumers keep working via the alias; shared StoreSummary verified identical shape) + +NOT touched (verified different, per exact-dupe rule): CreateCouponInput/UpdateCouponInput, CreateProductTagInput/UpdateProductTagInput, SlotSnippetInput, CreateSkuInput/CreateProductInput (sku- vs product-model drift); InferSelectModel *Row aliases (schema-bound per package); user-apis richer CouponValidationResult (different concept, same name — rename candidate only); backend banner-store Banner (subset shape); const-keys files (different key sets). + +[2026-09-04 23:58:00] FIX Phase 1 regression: my shape comparison was unreliable (shell-quoting artifact) and wrongly unified 2 drifted pairs. sqlite tsc went 4 -> 12 errors (coupon.ts x5, staff-user.ts x3). +- Coupon: admin.ts original had `skuIds: number[] | null`; canonical coupon.types.ts has `productIds: number[] | null` — RESTORED admin.ts local Coupon. +- StaffUser: admin.ts original had `staffRoleId: number | null`; canonical staff-user.types.ts has `staffRoleId: number` — RESTORED admin.ts local StaffUser. +- Verified truly identical (re-export kept): Banner, Complaint, ComplaintWithUser, Constant, ConstantUpdateResult, UserMiniInfo, StaffRole. + +[2026-09-04 23:59:00] PHASE 4: additive shared primitives + aliasing (zero consumer edits). +- NEW packages/shared/types/primitives.types.ts: MessageResponse {success, message}, IdName {id, name} (leaf module, no imports — no cycles) +- shared/types/index.ts: added export type * from './primitives.types'; +- shared/types/user.ts: 8 interfaces (UserAddressDeleteResponse, UserCancelOrderResponse, UserDeleteAccountResponse, UserPasswordUpdateResponse, UserPaymentFailResponse, UserPaymentVerifyResponse, UserRaiseComplaintResponse, UserUpdateNotesResponse) become export type X = MessageResponse +- shared/types/admin.ts: AdminOrderMessageResult becomes export type AdminOrderMessageResult = MessageResponse ; AdminVendorSnippetProduct becomes export type AdminVendorSnippetProduct = IdName +- apps/admin-ui/types/vendor-snippets.ts: VendorSnippetProduct becomes alias of shared IdName +- apps/admin-ui/components/ProductListDialog.tsx: local VendorSnippetProduct becomes alias of shared IdName +- apps/admin-ui/src/components/TagForm.tsx: StoreOption becomes alias of shared IdName +- apps/admin-ui/components/context/staff-auth-context.tsx: Staff becomes alias of shared IdName +- apps/backend/src/middleware/auth.middleware.ts: StaffContext becomes alias of shared IdName +DECISION (documented, not done): ui<->web-components prop mirrors left independent (no cross-dep between the RN and web UI packages; wiring one for 3 prop types is disproportionate). migrator TableInfo/ColumnInfo left (ColumnInfo field names differ per direction — unifying TableInfo alone would be wrong). CartData left (each app's CartItem element type differs). Drifted pairs (coupon/tag/slot/product inputs, store-helpers cache types, user-apis order relations) left per exact-dupe rule. + +[2026-09-05 00:02:00] FIX two regressions found by tsc verification: +(a) admin.ts used MessageResponse/IdName in aliases without importing them (export-from does not bring names into local scope) — added import type { MessageResponse, IdName } from './primitives.types' (re-export line kept). +(b) Pre-existing broken chain from prior centralization session (NOT mine, but fixed as part of unification): both store-helpers.ts files imported ProductTagData/TagProductMapping/UserNegativityData from shared without re-exporting, while both index.ts files re-export those names from store-helpers (TS2459 x3 in backend build). Added export type { ProductTagData, TagProductMapping, UserNegativityData } from '@packages/shared' to both store-helpers files. + +[2026-09-05 00:05:00] FIX two more gaps from prior centralization session (surfaced by my Phase 2 wiring): +(a) shared/types/app-common.types.ts was never added to shared/types/index.ts star exports — added export type * from './app-common.types'; (no name collisions verified). This makes LoginFormInputs/DropdownOption/CartIconProps/AddressFormProps/ComplaintFormProps/CartData importable from '@packages/shared'. +(b) user-ui prominent-api-hooks.ts declared AvailabilityEntry without export — added export keyword so centralSlotStore's import resolves. + +[2026-09-05 00:08:50] COMPLETED exact-duplicate type unification (Phases 1-4). +Centralized in @packages/shared and re-used: +- admin.ts: Banner, Complaint, ComplaintWithUser, Constant, ConstantUpdateResult, CouponValidationResult, UserMiniInfo, StaffRole → re-exports (Coupon + StaffUser KEPT local — verified drifted: skuIds vs productIds, staffRoleId nullable vs not) +- user.ts: UserBanner → alias of Banner +- NEW order.types.ts: PlacedOrder, CouponUsageWithCoupon, GetAllOrdersInput; both db packages import them (OrderWithCancellationData left local — extends drifted OrderWithFullData) +- StoreBasicData (both store-helpers) → alias of shared StoreSummary (verified identical shape) +- seed re-export chain repaired in both lib/seed.ts (was dangling after prior session's migration) +- user-ui: LoginCredentials/RegisterData → shared aliases; RedirectState canonical in AuthContext; LoginFormInputs (user-ui + web-ui) → shared app-common; Order/OrderItem → new src/types/orders.ts; AvailabilityEntry canonical in prominent-api-hooks +- primitives.types.ts (MessageResponse, IdName): 8 user.ts + AdminOrderMessageResult + AdminVendorSnippetProduct + 4 cross-file {id,name} types aliased +- Fixed as found: app-common.types.ts added to shared index star-exports; AvailabilityEntry export added in user-ui hooks; 3 dangling store-helpers re-exports repaired +Verification: backend 11, sqlite 4, user-ui 106, admin-ui 122 (all = baselines); pg 45 = 40 + 5 pg-coupon casts that reproduce with byte-restored admin.ts (pre-existing drift from prior session, documented in report §8). Zero errors mention any unified name. +Deliberately NOT unified (documented in repeat_types_glm.md §8 + change-log): drifted input types (coupon/tag/slot/product), InferSelectModel *Row aliases (schema-bound), ui<->web-components (no cross-dep), migrator ColumnInfo (field names differ per direction), CartData (element types differ), backend banner-store Banner (subset shape), const-keys files (different key sets). diff --git a/packages/db_helper_postgres/src/admin-apis/order.ts b/packages/db_helper_postgres/src/admin-apis/order.ts index 9b3c315..7185dee 100644 --- a/packages/db_helper_postgres/src/admin-apis/order.ts +++ b/packages/db_helper_postgres/src/admin-apis/order.ts @@ -25,6 +25,7 @@ import type { AdminRefundRecord, RefundStatus, PaymentStatus, + GetAllOrdersInput, } from '@packages/shared' import type { InferSelectModel } from 'drizzle-orm' @@ -427,16 +428,6 @@ export async function updateAddressCoords( return { success: result.length > 0 } } -type GetAllOrdersInput = { - cursor?: number - limit: number - slotId?: number | null - packagedFilter?: 'all' | 'packaged' | 'not_packaged' - deliveredFilter?: 'all' | 'delivered' | 'not_delivered' - cancellationFilter?: 'all' | 'cancelled' | 'not_cancelled' - flashDeliveryFilter?: 'all' | 'flash' | 'regular' -} - export async function getAllOrders(input: GetAllOrdersInput): Promise { const { cursor, diff --git a/packages/db_helper_postgres/src/lib/seed.ts b/packages/db_helper_postgres/src/lib/seed.ts index efafa89..b9f3cb8 100644 --- a/packages/db_helper_postgres/src/lib/seed.ts +++ b/packages/db_helper_postgres/src/lib/seed.ts @@ -2,6 +2,10 @@ import { db } from '../db/db_index' import { eq, and } from 'drizzle-orm' import type { UnitSeedData, StaffRoleName, StaffPermissionName, RolePermissionAssignment, KeyValSeedData } from '@packages/shared' +// Re-exported so the package index (`export { ... } from './src/lib/seed'`) +// keeps resolving to the single shared source. +export type { UnitSeedData, StaffRoleName, StaffPermissionName, RolePermissionAssignment, KeyValSeedData } from '@packages/shared' + // ============================================================================ // Unit Seed Helper // ============================================================================ diff --git a/packages/db_helper_postgres/src/stores/store-helpers.ts b/packages/db_helper_postgres/src/stores/store-helpers.ts index 132ea56..ad5d00e 100644 --- a/packages/db_helper_postgres/src/stores/store-helpers.ts +++ b/packages/db_helper_postgres/src/stores/store-helpers.ts @@ -14,7 +14,14 @@ import { userIncidents, } from '../db/schema' import { eq, and, gt, sql, inArray, isNotNull, asc, sum } from 'drizzle-orm' -import type { ProductTagData, TagProductMapping, UserNegativityData } from '@packages/shared' +import type { ProductTagData, TagProductMapping, UserNegativityData, StoreSummary } from '@packages/shared' + +// Re-exported so the package index (`export { ... } from './src/stores/store-helpers'`) +// keeps resolving to the single shared source. +export type { ProductTagData, TagProductMapping, UserNegativityData } from '@packages/shared' + +// StoreBasicData is exactly the shared StoreSummary shape — single source, same export name. +export type StoreBasicData = StoreSummary // ============================================================================ // BANNER STORE HELPERS @@ -57,12 +64,6 @@ export interface ProductBasicData { flashPrice: string | null } -export interface StoreBasicData { - id: number - name: string - description: string | null -} - export interface DeliverySlotData { productId: number id: number diff --git a/packages/db_helper_postgres/src/user-apis/order.ts b/packages/db_helper_postgres/src/user-apis/order.ts index 9c094de..c5b34ae 100644 --- a/packages/db_helper_postgres/src/user-apis/order.ts +++ b/packages/db_helper_postgres/src/user-apis/order.ts @@ -18,26 +18,10 @@ import { and, eq, inArray, desc, lte } from 'drizzle-orm' import type { UserOrderSummary, UserOrderDetail, + PlacedOrder, + CouponUsageWithCoupon, } from '@packages/shared' -export interface PlacedOrder { - id: number - userId: number - addressId: number - slotId: number | null - totalAmount: string - deliveryCharge: string - isCod: boolean - isOnlinePayment: boolean - paymentInfoId: number | null - readableId: number - userNotes: string | null - orderGroupId: string - orderGroupProportion: string - isFlashDelivery: boolean - createdAt: Date -} - export interface OrderWithRelations { id: number userId: number @@ -144,19 +128,6 @@ export interface CouponValidationResult { }> } -export interface CouponUsageWithCoupon { - id: number - couponId: number - orderId: number | null - coupon: { - id: number - couponCode: string - discountPercent: string | null - flatDiscount: string | null - maxValue: string | null - } -} - export async function validateAndGetCoupon( couponId: number | undefined, userId: number, diff --git a/packages/db_helper_sqlite/src/admin-apis/order.ts b/packages/db_helper_sqlite/src/admin-apis/order.ts index 40572b2..63d6e6a 100644 --- a/packages/db_helper_sqlite/src/admin-apis/order.ts +++ b/packages/db_helper_sqlite/src/admin-apis/order.ts @@ -25,6 +25,7 @@ import type { AdminRefundRecord, RefundStatus, PaymentStatus, + GetAllOrdersInput, } from '@packages/shared' import type { InferSelectModel } from 'drizzle-orm' import { coerceDate } from '../lib/date' @@ -441,16 +442,6 @@ export async function updateAddressCoords( return { success: result.length > 0 } } -type GetAllOrdersInput = { - cursor?: number - limit: number - slotId?: number | null - packagedFilter?: 'all' | 'packaged' | 'not_packaged' - deliveredFilter?: 'all' | 'delivered' | 'not_delivered' - cancellationFilter?: 'all' | 'cancelled' | 'not_cancelled' - flashDeliveryFilter?: 'all' | 'flash' | 'regular' -} - export async function getAllOrders(input: GetAllOrdersInput): Promise { const { cursor, diff --git a/packages/db_helper_sqlite/src/lib/seed.ts b/packages/db_helper_sqlite/src/lib/seed.ts index efafa89..b9f3cb8 100644 --- a/packages/db_helper_sqlite/src/lib/seed.ts +++ b/packages/db_helper_sqlite/src/lib/seed.ts @@ -2,6 +2,10 @@ import { db } from '../db/db_index' import { eq, and } from 'drizzle-orm' import type { UnitSeedData, StaffRoleName, StaffPermissionName, RolePermissionAssignment, KeyValSeedData } from '@packages/shared' +// Re-exported so the package index (`export { ... } from './src/lib/seed'`) +// keeps resolving to the single shared source. +export type { UnitSeedData, StaffRoleName, StaffPermissionName, RolePermissionAssignment, KeyValSeedData } from '@packages/shared' + // ============================================================================ // Unit Seed Helper // ============================================================================ diff --git a/packages/db_helper_sqlite/src/stores/store-helpers.ts b/packages/db_helper_sqlite/src/stores/store-helpers.ts index 8c6939b..788a297 100644 --- a/packages/db_helper_sqlite/src/stores/store-helpers.ts +++ b/packages/db_helper_sqlite/src/stores/store-helpers.ts @@ -17,7 +17,14 @@ import { } from '../db/schema' import { eq, and, gt, sql, isNotNull, asc } from 'drizzle-orm' import { composeSkuName, composeUnitNotation } from '../lib/sku-features' -import type { ProductTagData, TagProductMapping, UserNegativityData } from '@packages/shared' +import type { ProductTagData, TagProductMapping, UserNegativityData, StoreSummary } from '@packages/shared' + +// Re-exported so the package index (`export { ... } from './src/stores/store-helpers'`) +// keeps resolving to the single shared source. +export type { ProductTagData, TagProductMapping, UserNegativityData } from '@packages/shared' + +// StoreBasicData is exactly the shared StoreSummary shape — single source, same export name. +export type StoreBasicData = StoreSummary // ============================================================================ // BANNER STORE HELPERS @@ -75,12 +82,6 @@ export interface AvailabilityCacheData { isSuspended: boolean } -export interface StoreBasicData { - id: number - name: string - description: string | null -} - export interface DeliverySlotData { skuId: number id: number diff --git a/packages/db_helper_sqlite/src/user-apis/order.ts b/packages/db_helper_sqlite/src/user-apis/order.ts index 0db4c32..c171ca5 100644 --- a/packages/db_helper_sqlite/src/user-apis/order.ts +++ b/packages/db_helper_sqlite/src/user-apis/order.ts @@ -19,29 +19,13 @@ import { and, eq, inArray, desc, sql } from 'drizzle-orm' import type { UserOrderSummary, UserOrderDetail, + PlacedOrder, + CouponUsageWithCoupon, } from '@packages/shared' import { coerceDate } from '../lib/date' import { runBatched } from '../lib/run-batched' import { composeSkuName, composeUnitNotation } from '../lib/sku-features' -export interface PlacedOrder { - id: number - userId: number - addressId: number - slotId: number | null - totalAmount: string - deliveryCharge: string - isCod: boolean - isOnlinePayment: boolean - paymentInfoId: number | null - readableId: number - userNotes: string | null - orderGroupId: string - orderGroupProportion: string - isFlashDelivery: boolean - createdAt: Date -} - export interface OrderWithRelations { id: number userId: number @@ -154,19 +138,6 @@ export interface CouponValidationResult { }> } -export interface CouponUsageWithCoupon { - id: number - couponId: number - orderId: number | null - coupon: { - id: number - couponCode: string - discountPercent: string | null - flatDiscount: string | null - maxValue: string | null - } -} - export async function validateAndGetCoupon( couponId: number | undefined, userId: number, diff --git a/packages/shared/types/admin.ts b/packages/shared/types/admin.ts index 217b806..1492d22 100644 --- a/packages/shared/types/admin.ts +++ b/packages/shared/types/admin.ts @@ -1,45 +1,18 @@ // Admin-related types +// (Entity shapes live in the dedicated per-domain files — re-exported here +// so existing `@packages/shared` consumers keep working from one surface.) -export interface Banner { - id: number; - name: string; - imageUrl: string; - description: string | null; - skuIds: number[] | null; - redirectUrl: string | null; - serialNum: number | null; - isActive: boolean; - createdAt: Date; - lastUpdated: Date; -} - -export interface Complaint { - id: number; - complaintBody: string; - userId: number; - orderId: number | null; - isResolved: boolean; - response: string | null; - createdAt: Date; - images: string[] | null; -} - -export interface ComplaintWithUser extends Complaint { - userName: string | null; - userMobile: string | null; -} - -export interface Constant { - key: string; - value: any; -} - -export interface ConstantUpdateResult { - success: boolean; - updatedCount: number; - keys: string[]; -} +import type { MessageResponse, IdName } from './primitives.types' +export type { Banner } from './banner.types' +export type { Complaint, ComplaintWithUser } from './complaint.types' +export type { Constant, ConstantUpdateResult } from './const.types' +export type { CouponValidationResult, UserMiniInfo } from './coupon.types' +export type { StaffRole } from './staff-user.types' +export type { MessageResponse, IdName } from './primitives.types' +// NOTE: Coupon and StaffUser intentionally keep LOCAL declarations below — +// the dedicated files drifted (productIds vs skuIds; staffRoleId nullable vs +// not) and sqlite consumers depend on these exact shapes. export interface Coupon { id: number; couponCode: string; @@ -58,17 +31,12 @@ export interface Coupon { createdBy: number; } -export interface CouponValidationResult { - valid: boolean; - message?: string; - discountAmount?: number; - coupon?: Partial; -} - -export interface UserMiniInfo { +export interface StaffUser { id: number; name: string; - mobile: string | null; + password: string; + staffRoleId: number | null; + createdAt: Date; } export interface Store { @@ -81,19 +49,6 @@ export interface Store { // updatedAt: Date; } -export interface StaffUser { - id: number; - name: string; - password: string; - staffRoleId: number | null; - createdAt: Date; -} - -export interface StaffRole { - id: number; - roleName: string; -} - export interface AdminOrderRow { id: number; userId: number; @@ -232,10 +187,7 @@ export interface AdminOrderItemPackagingResult { updated: boolean; } -export interface AdminOrderMessageResult { - success: boolean; - message: string; -} +export type AdminOrderMessageResult = MessageResponse export interface AdminOrderBasicResult { success: boolean; @@ -601,10 +553,7 @@ export interface AdminVendorSnippetWithSlot extends AdminVendorSnippet { slot: AdminDeliverySlot | null; } -export interface AdminVendorSnippetProduct { - id: number; - name: string; -} +export type AdminVendorSnippetProduct = IdName export interface AdminVendorSnippetWithProducts extends AdminVendorSnippetWithSlot { accessUrl: string; diff --git a/packages/shared/types/index.ts b/packages/shared/types/index.ts index 55fae80..d88e642 100644 --- a/packages/shared/types/index.ts +++ b/packages/shared/types/index.ts @@ -10,6 +10,8 @@ export type * from './store.types'; // Shared cross-cutting types — import from '@packages/shared' anywhere: export type * from './upload.types'; // ContextString, UploadInput, UploadBatchInput, UploadResult +export type * from './app-common.types'; // LoginFormInputs, DropdownOption, CartIconProps, AddressFormProps, CartData +export type * from './order.types'; // PlacedOrder, CouponUsageWithCoupon, GetAllOrdersInput export type * from './seed.types'; // UnitSeedData, StaffRoleName, StaffPermissionName, RolePermissionAssignment, KeyValSeedData export type * from './inputs.types'; // CreateBannerInput, UpdateBannerInput, CreateStoreInput, Login/Register requests export type * from './cache.types'; // ProductTagData, TagProductMapping, UserNegativityData (truly identical subset) diff --git a/packages/shared/types/order.types.ts b/packages/shared/types/order.types.ts new file mode 100644 index 0000000..abe6701 --- /dev/null +++ b/packages/shared/types/order.types.ts @@ -0,0 +1,49 @@ +/** + * Order-domain shared types + * Were identically duplicated in db_helper_sqlite and db_helper_postgres. + * Canonical: import these from @packages/shared instead of redeclaring locally. + * NOTE: OrderWithFullData / OrderWithCancellationData / OrderWithRelations are + * intentionally NOT here — they drift between the sku-model (sqlite) and + * product-model (postgres) schemas and keep their local defs. + */ + +export interface PlacedOrder { + id: number + userId: number + addressId: number + slotId: number | null + totalAmount: string + deliveryCharge: string + isCod: boolean + isOnlinePayment: boolean + paymentInfoId: number | null + readableId: number + userNotes: string | null + orderGroupId: string + orderGroupProportion: string + isFlashDelivery: boolean + createdAt: Date +} + +export interface CouponUsageWithCoupon { + id: number + couponId: number + orderId: number | null + coupon: { + id: number + couponCode: string + discountPercent: string | null + flatDiscount: string | null + maxValue: string | null + } +} + +export type GetAllOrdersInput = { + cursor?: number + limit: number + slotId?: number | null + packagedFilter?: 'all' | 'packaged' | 'not_packaged' + deliveredFilter?: 'all' | 'delivered' | 'not_delivered' + cancellationFilter?: 'all' | 'cancelled' | 'not_cancelled' + flashDeliveryFilter?: 'all' | 'flash' | 'regular' +} diff --git a/packages/shared/types/primitives.types.ts b/packages/shared/types/primitives.types.ts new file mode 100644 index 0000000..104e069 --- /dev/null +++ b/packages/shared/types/primitives.types.ts @@ -0,0 +1,15 @@ +/** + * Primitive shared shapes + * Leaf module (no imports) — safe to import from anywhere without cycles. + * Domain types that are exactly these shapes alias them instead of redeclaring. + */ + +export interface MessageResponse { + success: boolean + message: string +} + +export interface IdName { + id: number + name: string +} diff --git a/packages/shared/types/user.ts b/packages/shared/types/user.ts index 6eed4c5..3279a2a 100644 --- a/packages/shared/types/user.ts +++ b/packages/shared/types/user.ts @@ -1,5 +1,12 @@ // User-related types +import type { MessageResponse } from './primitives.types' + +import type { Banner } from './banner.types' + +// UserBanner is exactly the shared Banner shape — single source in banner.types.ts +export type UserBanner = Banner + export interface User { id: number; name: string | null; @@ -58,10 +65,7 @@ export interface UserAddressesResponse { data: UserAddress[]; } -export interface UserAddressDeleteResponse { - success: boolean; - message: string; -} +export type UserAddressDeleteResponse = MessageResponse export interface Product { id: number; @@ -116,19 +120,6 @@ export interface Payment { createdAt: Date; } -export interface UserBanner { - id: number; - name: string; - imageUrl: string; - description: string | null; - skuIds: number[] | null; - redirectUrl: string | null; - serialNum: number | null; - isActive: boolean; - createdAt: Date; - lastUpdated: Date; -} - export interface UserBannersResponse { banners: UserBanner[]; } @@ -146,10 +137,7 @@ export interface UserComplaintsResponse { complaints: UserComplaint[]; } -export interface UserRaiseComplaintResponse { - success: boolean; - message: string; -} +export type UserRaiseComplaintResponse = MessageResponse export interface UserTagSummary { id: number; @@ -368,15 +356,9 @@ export interface UserPaymentOrderResponse { key: string | undefined; } -export interface UserPaymentVerifyResponse { - success: boolean; - message: string; -} +export type UserPaymentVerifyResponse = MessageResponse -export interface UserPaymentFailResponse { - success: boolean; - message: string; -} +export type UserPaymentFailResponse = MessageResponse export interface UserAuthProfile { id: number; @@ -414,15 +396,9 @@ export interface UserOtpVerifyResponse { }; } -export interface UserPasswordUpdateResponse { - success: boolean; - message: string; -} +export type UserPasswordUpdateResponse = MessageResponse -export interface UserDeleteAccountResponse { - success: boolean; - message: string; -} +export type UserDeleteAccountResponse = MessageResponse export interface UserCouponUsage { id: number; @@ -574,12 +550,6 @@ export interface UserOrderDetail extends UserOrderSummary { orderAmount: number; } -export interface UserCancelOrderResponse { - success: boolean; - message: string; -} +export type UserCancelOrderResponse = MessageResponse -export interface UserUpdateNotesResponse { - success: boolean; - message: string; -} +export type UserUpdateNotesResponse = MessageResponse