diff --git a/app/composables/graphql/generated.ts b/app/composables/graphql/generated.ts index ef2316e..1d0fb90 100644 --- a/app/composables/graphql/generated.ts +++ b/app/composables/graphql/generated.ts @@ -62,6 +62,30 @@ export type BonusTransaction = { userId: Scalars['ID']['output']; }; +export type Cart = { + __typename?: 'Cart'; + createdAt: Scalars['DateTime']['output']; + deliveryAddress?: Maybe; + deliveryAddressId?: Maybe; + id: Scalars['ID']['output']; + items: Array; + updatedAt: Scalars['DateTime']['output']; + userId: Scalars['ID']['output']; +}; + +export type CartItem = { + __typename?: 'CartItem'; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + isCustomizable: Scalars['Boolean']['output']; + parameters: Scalars['JSON']['output']; + productId: Scalars['ID']['output']; + productName: Scalars['String']['output']; + quantity: Scalars['Float']['output']; + sku: Scalars['String']['output']; + updatedAt: Scalars['DateTime']['output']; +}; + export type Company = { __typename?: 'Company'; id: Scalars['ID']['output']; @@ -180,7 +204,9 @@ export type Mutation = { __typename?: 'Mutation'; acceptInvitation: User; addBonusTransaction: BonusTransaction; + addProductToCart: Cart; blockOrder: Order; + clearCart: Cart; clientReviewOrder: Order; completeOrder: Order; connectMessenger: MessengerConnection; @@ -192,15 +218,18 @@ export type Mutation = { managerFinalizeOrder: Order; managerSetOrderOffer: Order; registerSelf: RegistrationRequest; + removeCartItem: Cart; requestLoginCode: AuthCodeRequestResult; requestRewardWithdrawal: RewardWithdrawalRequest; reviewRegistrationRequest: RegistrationRequest; reviewRewardWithdrawal: RewardWithdrawalRequest; sendTestMessengerMessage: MessengerDispatchResult; + setCartDeliveryAddress: Cart; setMyDefaultDeliveryAddress: DeliveryAddress; startOrderWork: Order; submitCalculationOrder: Order; submitReadyOrder: Order; + updateCartItemQuantity: Cart; upsertMyCounterpartyProfile: CounterpartyProfile; verifyLoginCode: AuthSession; }; @@ -216,6 +245,11 @@ export type MutationAddBonusTransactionArgs = { }; +export type MutationAddProductToCartArgs = { + productId: Scalars['ID']['input']; +}; + + export type MutationBlockOrderArgs = { input: BlockOrderInput; }; @@ -278,6 +312,11 @@ export type MutationRegisterSelfArgs = { }; +export type MutationRemoveCartItemArgs = { + productId: Scalars['ID']['input']; +}; + + export type MutationRequestLoginCodeArgs = { input: RequestLoginCodeInput; }; @@ -305,6 +344,11 @@ export type MutationSendTestMessengerMessageArgs = { }; +export type MutationSetCartDeliveryAddressArgs = { + addressId?: InputMaybe; +}; + + export type MutationSetMyDefaultDeliveryAddressArgs = { addressId: Scalars['ID']['input']; }; @@ -325,6 +369,11 @@ export type MutationSubmitReadyOrderArgs = { }; +export type MutationUpdateCartItemQuantityArgs = { + input: UpdateCartItemQuantityInput; +}; + + export type MutationUpsertMyCounterpartyProfileArgs = { input: UpsertMyCounterpartyProfileInput; }; @@ -430,6 +479,7 @@ export type Query = { managerNotificationHistory: Array; managerOrders: Array; me?: Maybe; + myCart: Cart; myCounterpartyProfile?: Maybe; myCurrentOrders: Array; myDeliveryAddresses: Array; @@ -564,6 +614,11 @@ export type SubmitReadyOrderInput = { items: Array; }; +export type UpdateCartItemQuantityInput = { + productId: Scalars['ID']['input']; + quantity: Scalars['Float']['input']; +}; + export type UpsertMyCounterpartyProfileInput = { bankName: Scalars['String']['input']; bik: Scalars['String']['input']; @@ -645,6 +700,44 @@ export type VerifyLoginCodeMutationVariables = Exact<{ export type VerifyLoginCodeMutation = { __typename?: 'Mutation', verifyLoginCode: { __typename?: 'AuthSession', accessToken: string, expiresAt: any, user: { __typename?: 'User', id: string, email: string, fullName: string, role: UserRole, company?: { __typename?: 'Company', id: string } | null } } }; +export type AddProductToCartMutationVariables = Exact<{ + productId: Scalars['ID']['input']; +}>; + + +export type AddProductToCartMutation = { __typename?: 'Mutation', addProductToCart: { __typename?: 'Cart', id: string, userId: string, deliveryAddressId?: string | null, updatedAt: any, items: Array<{ __typename?: 'CartItem', id: string, productId: string, productName: string, sku: string, isCustomizable: boolean, quantity: number, parameters: any, updatedAt: any }> } }; + +export type ClearCartMutationVariables = Exact<{ [key: string]: never; }>; + + +export type ClearCartMutation = { __typename?: 'Mutation', clearCart: { __typename?: 'Cart', id: string, userId: string, deliveryAddressId?: string | null, updatedAt: any, items: Array<{ __typename?: 'CartItem', id: string, productId: string, productName: string, sku: string, isCustomizable: boolean, quantity: number, parameters: any, updatedAt: any }> } }; + +export type MyCartQueryVariables = Exact<{ [key: string]: never; }>; + + +export type MyCartQuery = { __typename?: 'Query', myCart: { __typename?: 'Cart', id: string, userId: string, deliveryAddressId?: string | null, updatedAt: any, items: Array<{ __typename?: 'CartItem', id: string, productId: string, productName: string, sku: string, isCustomizable: boolean, quantity: number, parameters: any, updatedAt: any }> } }; + +export type RemoveCartItemMutationVariables = Exact<{ + productId: Scalars['ID']['input']; +}>; + + +export type RemoveCartItemMutation = { __typename?: 'Mutation', removeCartItem: { __typename?: 'Cart', id: string, userId: string, deliveryAddressId?: string | null, updatedAt: any, items: Array<{ __typename?: 'CartItem', id: string, productId: string, productName: string, sku: string, isCustomizable: boolean, quantity: number, parameters: any, updatedAt: any }> } }; + +export type SetCartDeliveryAddressMutationVariables = Exact<{ + addressId?: InputMaybe; +}>; + + +export type SetCartDeliveryAddressMutation = { __typename?: 'Mutation', setCartDeliveryAddress: { __typename?: 'Cart', id: string, userId: string, deliveryAddressId?: string | null, updatedAt: any, items: Array<{ __typename?: 'CartItem', id: string, productId: string, productName: string, sku: string, isCustomizable: boolean, quantity: number, parameters: any, updatedAt: any }> } }; + +export type UpdateCartItemQuantityMutationVariables = Exact<{ + input: UpdateCartItemQuantityInput; +}>; + + +export type UpdateCartItemQuantityMutation = { __typename?: 'Mutation', updateCartItemQuantity: { __typename?: 'Cart', id: string, userId: string, deliveryAddressId?: string | null, updatedAt: any, items: Array<{ __typename?: 'CartItem', id: string, productId: string, productName: string, sku: string, isCustomizable: boolean, quantity: number, parameters: any, updatedAt: any }> } }; + export type ClientProductsQueryVariables = Exact<{ [key: string]: never; }>; @@ -1015,6 +1108,252 @@ export function useVerifyLoginCodeMutation(options: VueApolloComposable.UseMutat return VueApolloComposable.useMutation(VerifyLoginCodeDocument, options); } export type VerifyLoginCodeMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn; +export const AddProductToCartDocument = gql` + mutation AddProductToCart($productId: ID!) { + addProductToCart(productId: $productId) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} + `; + +/** + * __useAddProductToCartMutation__ + * + * To run a mutation, you first call `useAddProductToCartMutation` within a Vue component and pass it any options that fit your needs. + * When your component renders, `useAddProductToCartMutation` returns an object that includes: + * - A mutate function that you can call at any time to execute the mutation + * - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return + * + * @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options; + * + * @example + * const { mutate, loading, error, onDone } = useAddProductToCartMutation({ + * variables: { + * productId: // value for 'productId' + * }, + * }); + */ +export function useAddProductToCartMutation(options: VueApolloComposable.UseMutationOptions | ReactiveFunction> = {}) { + return VueApolloComposable.useMutation(AddProductToCartDocument, options); +} +export type AddProductToCartMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn; +export const ClearCartDocument = gql` + mutation ClearCart { + clearCart { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} + `; + +/** + * __useClearCartMutation__ + * + * To run a mutation, you first call `useClearCartMutation` within a Vue component and pass it any options that fit your needs. + * When your component renders, `useClearCartMutation` returns an object that includes: + * - A mutate function that you can call at any time to execute the mutation + * - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return + * + * @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options; + * + * @example + * const { mutate, loading, error, onDone } = useClearCartMutation(); + */ +export function useClearCartMutation(options: VueApolloComposable.UseMutationOptions | ReactiveFunction> = {}) { + return VueApolloComposable.useMutation(ClearCartDocument, options); +} +export type ClearCartMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn; +export const MyCartDocument = gql` + query MyCart { + myCart { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} + `; + +/** + * __useMyCartQuery__ + * + * To run a query within a Vue component, call `useMyCartQuery` and pass it any options that fit your needs. + * When your component renders, `useMyCartQuery` returns an object from Apollo Client that contains result, loading and error properties + * you can use to render your UI. + * + * @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options; + * + * @example + * const { result, loading, error } = useMyCartQuery(); + */ +export function useMyCartQuery(options: VueApolloComposable.UseQueryOptions | VueCompositionApi.Ref> | ReactiveFunction> = {}) { + return VueApolloComposable.useQuery(MyCartDocument, {}, options); +} +export function useMyCartLazyQuery(options: VueApolloComposable.UseQueryOptions | VueCompositionApi.Ref> | ReactiveFunction> = {}) { + return VueApolloComposable.useLazyQuery(MyCartDocument, {}, options); +} +export type MyCartQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn; +export const RemoveCartItemDocument = gql` + mutation RemoveCartItem($productId: ID!) { + removeCartItem(productId: $productId) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} + `; + +/** + * __useRemoveCartItemMutation__ + * + * To run a mutation, you first call `useRemoveCartItemMutation` within a Vue component and pass it any options that fit your needs. + * When your component renders, `useRemoveCartItemMutation` returns an object that includes: + * - A mutate function that you can call at any time to execute the mutation + * - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return + * + * @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options; + * + * @example + * const { mutate, loading, error, onDone } = useRemoveCartItemMutation({ + * variables: { + * productId: // value for 'productId' + * }, + * }); + */ +export function useRemoveCartItemMutation(options: VueApolloComposable.UseMutationOptions | ReactiveFunction> = {}) { + return VueApolloComposable.useMutation(RemoveCartItemDocument, options); +} +export type RemoveCartItemMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn; +export const SetCartDeliveryAddressDocument = gql` + mutation SetCartDeliveryAddress($addressId: ID) { + setCartDeliveryAddress(addressId: $addressId) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} + `; + +/** + * __useSetCartDeliveryAddressMutation__ + * + * To run a mutation, you first call `useSetCartDeliveryAddressMutation` within a Vue component and pass it any options that fit your needs. + * When your component renders, `useSetCartDeliveryAddressMutation` returns an object that includes: + * - A mutate function that you can call at any time to execute the mutation + * - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return + * + * @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options; + * + * @example + * const { mutate, loading, error, onDone } = useSetCartDeliveryAddressMutation({ + * variables: { + * addressId: // value for 'addressId' + * }, + * }); + */ +export function useSetCartDeliveryAddressMutation(options: VueApolloComposable.UseMutationOptions | ReactiveFunction> = {}) { + return VueApolloComposable.useMutation(SetCartDeliveryAddressDocument, options); +} +export type SetCartDeliveryAddressMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn; +export const UpdateCartItemQuantityDocument = gql` + mutation UpdateCartItemQuantity($input: UpdateCartItemQuantityInput!) { + updateCartItemQuantity(input: $input) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} + `; + +/** + * __useUpdateCartItemQuantityMutation__ + * + * To run a mutation, you first call `useUpdateCartItemQuantityMutation` within a Vue component and pass it any options that fit your needs. + * When your component renders, `useUpdateCartItemQuantityMutation` returns an object that includes: + * - A mutate function that you can call at any time to execute the mutation + * - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return + * + * @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options; + * + * @example + * const { mutate, loading, error, onDone } = useUpdateCartItemQuantityMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useUpdateCartItemQuantityMutation(options: VueApolloComposable.UseMutationOptions | ReactiveFunction> = {}) { + return VueApolloComposable.useMutation(UpdateCartItemQuantityDocument, options); +} +export type UpdateCartItemQuantityMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn; export const ClientProductsDocument = gql` query ClientProducts { clientProducts { diff --git a/app/composables/useClientCart.ts b/app/composables/useClientCart.ts index 288136f..b002892 100644 --- a/app/composables/useClientCart.ts +++ b/app/composables/useClientCart.ts @@ -1,14 +1,27 @@ +import { + AddProductToCartDocument, + ClearCartDocument, + MyCartDocument, + RemoveCartItemDocument, + SetCartDeliveryAddressDocument, + UpdateCartItemQuantityDocument, + type MyCartQuery, +} from '~/composables/graphql/generated'; +import { useGqlClient } from '~/composables/useGqlClient'; + +type CartParameters = { + width: number; + thickness: number; + color: string; +}; + export type ClientCartItem = { productId: string; productName: string; sku: string; isCustomizable: boolean; quantity: number; - parameters: { - width: number; - thickness: number; - color: string; - }; + parameters: CartParameters; }; function normalizeQuantity(value: number) { @@ -19,8 +32,33 @@ function normalizeQuantity(value: number) { return Math.floor(value); } +function normalizeParameters(value: unknown): CartParameters { + const source = (value && typeof value === 'object') ? value as Partial : {}; + + return { + width: Number(source.width ?? 100), + thickness: Number(source.thickness ?? 50), + color: typeof source.color === 'string' ? source.color : 'прозрачный', + }; +} + +function mapCartItem(item: MyCartQuery['myCart']['items'][number]): ClientCartItem { + return { + productId: item.productId, + productName: item.productName, + sku: item.sku, + isCustomizable: item.isCustomizable, + quantity: Number(item.quantity), + parameters: normalizeParameters(item.parameters), + }; +} + export function useClientCart() { + const client = useGqlClient(); const items = useState('client-cart-items', () => []); + const selectedDeliveryAddressId = useState('client-cart-delivery-address-id', () => ''); + const initialized = useState('client-cart-initialized', () => false); + const loading = useState('client-cart-loading', () => false); const totalPositions = computed(() => items.value.length); const totalItems = computed(() => items.value.reduce((sum, item) => sum + item.quantity, 0)); @@ -28,94 +66,138 @@ export function useClientCart() { items.value.reduce((sum, item) => sum + item.quantity * item.parameters.width * item.parameters.thickness, 0), ); + function applyCart(cart: MyCartQuery['myCart']) { + items.value = cart.items.map(mapCartItem); + selectedDeliveryAddressId.value = cart.deliveryAddressId ?? ''; + initialized.value = true; + } + + async function fetchCart(force = false) { + if (loading.value) { + return; + } + + if (initialized.value && !force) { + return; + } + + loading.value = true; + + try { + const { data } = await client.query({ + query: MyCartDocument, + fetchPolicy: 'network-only', + }); + + if (data?.myCart) { + applyCart(data.myCart); + } + } finally { + loading.value = false; + } + } + function getQuantity(productId: string) { return items.value.find((item) => item.productId === productId)?.quantity ?? 0; } - function addProduct(product: { + async function addProduct(product: { id: string; name: string; sku: string; isCustomizable: boolean; }) { - const existing = items.value.find((item) => item.productId === product.id); - if (existing) { - existing.quantity += 1; - return; - } - - items.value.push({ - productId: product.id, - productName: product.name, - sku: product.sku, - isCustomizable: product.isCustomizable, - quantity: 1, - parameters: { - width: 100, - thickness: 50, - color: 'прозрачный', - }, + const { data } = await client.mutate({ + mutation: AddProductToCartDocument, + variables: { productId: product.id }, + fetchPolicy: 'no-cache', }); + + if (data?.addProductToCart) { + applyCart(data.addProductToCart); + } } - function setQuantity(productId: string, quantity: number) { - const existing = items.value.find((item) => item.productId === productId); - if (!existing) { - return; - } - + async function setQuantity(productId: string, quantity: number) { const normalizedQuantity = normalizeQuantity(quantity); - if (normalizedQuantity === 0) { - removeProduct(productId); - return; - } + const { data } = await client.mutate({ + mutation: UpdateCartItemQuantityDocument, + variables: { + input: { + productId, + quantity: normalizedQuantity, + }, + }, + fetchPolicy: 'no-cache', + }); - existing.quantity = normalizedQuantity; + if (data?.updateCartItemQuantity) { + applyCart(data.updateCartItemQuantity); + } } - function incrementQuantity(productId: string) { - const existing = items.value.find((item) => item.productId === productId); - if (!existing) { - return; - } - - existing.quantity += 1; + async function incrementQuantity(productId: string) { + await setQuantity(productId, getQuantity(productId) + 1); } - function decrementQuantity(productId: string) { - const existing = items.value.find((item) => item.productId === productId); - if (!existing) { - return; - } - - const normalizedQuantity = normalizeQuantity(existing.quantity - 1); - if (normalizedQuantity === 0) { - removeProduct(productId); - return; - } - - existing.quantity = normalizedQuantity; + async function decrementQuantity(productId: string) { + await setQuantity(productId, getQuantity(productId) - 1); } - function removeProduct(productId: string) { - items.value = items.value.filter((item) => item.productId !== productId); + async function removeProduct(productId: string) { + const { data } = await client.mutate({ + mutation: RemoveCartItemDocument, + variables: { productId }, + fetchPolicy: 'no-cache', + }); + + if (data?.removeCartItem) { + applyCart(data.removeCartItem); + } } - function clearCart() { - items.value = []; + async function setDeliveryAddress(addressId: string | null) { + const { data } = await client.mutate({ + mutation: SetCartDeliveryAddressDocument, + variables: { addressId: addressId || null }, + fetchPolicy: 'no-cache', + }); + + if (data?.setCartDeliveryAddress) { + applyCart(data.setCartDeliveryAddress); + } + } + + async function clearCart() { + const { data } = await client.mutate({ + mutation: ClearCartDocument, + fetchPolicy: 'no-cache', + }); + + if (data?.clearCart) { + applyCart(data.clearCart); + } + } + + if (!initialized.value && !loading.value) { + void fetchCart(); } return { items, + loading, + selectedDeliveryAddressId, totalPositions, totalItems, totalVolume, + fetchCart, addProduct, setQuantity, incrementQuantity, decrementQuantity, removeProduct, clearCart, + setDeliveryAddress, getQuantity, }; } diff --git a/app/pages/cart.vue b/app/pages/cart.vue index 06bcc34..8dffa46 100644 --- a/app/pages/cart.vue +++ b/app/pages/cart.vue @@ -16,6 +16,8 @@ const deliveryAddressesQuery = useQuery(MyDeliveryAddressesDocument); const { items: cartItems, + fetchCart, + selectedDeliveryAddressId, totalPositions, totalItems, totalVolume, @@ -23,9 +25,9 @@ const { decrementQuantity, removeProduct, clearCart, + setDeliveryAddress, } = useClientCart(); -const selectedDeliveryAddressId = ref(''); const sending = ref(false); const success = ref(''); const errorMessage = ref(''); @@ -35,9 +37,11 @@ const hasDeliveryAddresses = computed(() => deliveryAddresses.value.length > 0); watch( deliveryAddresses, - (addresses) => { + async (addresses) => { if (addresses.length < 1) { - selectedDeliveryAddressId.value = ''; + if (selectedDeliveryAddressId.value) { + await setDeliveryAddress(null); + } return; } @@ -47,11 +51,15 @@ watch( } const defaultAddress = addresses.find((address) => address.isDefault); - selectedDeliveryAddressId.value = defaultAddress?.id || addresses[0]?.id || ''; + await setDeliveryAddress(defaultAddress?.id || addresses[0]?.id || null); }, { immediate: true }, ); +onMounted(() => { + void fetchCart(true); +}); + function lineVolume(productId: string) { const item = cartItems.value.find((entry) => entry.productId === productId); if (!item) { @@ -64,19 +72,25 @@ function lineVolume(productId: string) { function increment(productId: string) { success.value = ''; errorMessage.value = ''; - incrementQuantity(productId); + void incrementQuantity(productId); } function decrement(productId: string) { success.value = ''; errorMessage.value = ''; - decrementQuantity(productId); + void decrementQuantity(productId); } function removeFromCart(productId: string) { success.value = ''; errorMessage.value = ''; - removeProduct(productId); + void removeProduct(productId); +} + +function selectDeliveryAddress(addressId: string) { + success.value = ''; + errorMessage.value = ''; + void setDeliveryAddress(addressId); } async function submitCart() { @@ -126,7 +140,7 @@ async function submitCart() { } sending.value = false; - clearCart(); + await clearCart(); success.value = `Отправлено заявок: ${createdCodes.length}. Статус: уточнение цены.`; } @@ -160,11 +174,11 @@ async function submitCart() { class="flex cursor-pointer items-start gap-3 rounded-2xl bg-white p-3 transition hover:shadow-md" > diff --git a/graphql/operations/cart/add-product-to-cart.graphql b/graphql/operations/cart/add-product-to-cart.graphql new file mode 100644 index 0000000..9e35598 --- /dev/null +++ b/graphql/operations/cart/add-product-to-cart.graphql @@ -0,0 +1,18 @@ +mutation AddProductToCart($productId: ID!) { + addProductToCart(productId: $productId) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} diff --git a/graphql/operations/cart/clear-cart.graphql b/graphql/operations/cart/clear-cart.graphql new file mode 100644 index 0000000..0a15c4c --- /dev/null +++ b/graphql/operations/cart/clear-cart.graphql @@ -0,0 +1,18 @@ +mutation ClearCart { + clearCart { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} diff --git a/graphql/operations/cart/my-cart.graphql b/graphql/operations/cart/my-cart.graphql new file mode 100644 index 0000000..d521dc6 --- /dev/null +++ b/graphql/operations/cart/my-cart.graphql @@ -0,0 +1,18 @@ +query MyCart { + myCart { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} diff --git a/graphql/operations/cart/remove-cart-item.graphql b/graphql/operations/cart/remove-cart-item.graphql new file mode 100644 index 0000000..685b15c --- /dev/null +++ b/graphql/operations/cart/remove-cart-item.graphql @@ -0,0 +1,18 @@ +mutation RemoveCartItem($productId: ID!) { + removeCartItem(productId: $productId) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} diff --git a/graphql/operations/cart/set-cart-delivery-address.graphql b/graphql/operations/cart/set-cart-delivery-address.graphql new file mode 100644 index 0000000..7d7e38d --- /dev/null +++ b/graphql/operations/cart/set-cart-delivery-address.graphql @@ -0,0 +1,18 @@ +mutation SetCartDeliveryAddress($addressId: ID) { + setCartDeliveryAddress(addressId: $addressId) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} diff --git a/graphql/operations/cart/update-cart-item-quantity.graphql b/graphql/operations/cart/update-cart-item-quantity.graphql new file mode 100644 index 0000000..a7497c5 --- /dev/null +++ b/graphql/operations/cart/update-cart-item-quantity.graphql @@ -0,0 +1,18 @@ +mutation UpdateCartItemQuantity($input: UpdateCartItemQuantityInput!) { + updateCartItemQuantity(input: $input) { + id + userId + deliveryAddressId + items { + id + productId + productName + sku + isCustomizable + quantity + parameters + updatedAt + } + updatedAt + } +} diff --git a/graphql/schema.graphql b/graphql/schema.graphql index a0c2b32..2da2997 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -191,6 +191,28 @@ type Product { availableInWarehouses: [ProductWarehouseBalance!]! } +type CartItem { + id: ID! + productId: ID! + productName: String! + sku: String! + isCustomizable: Boolean! + quantity: Float! + parameters: JSON! + createdAt: DateTime! + updatedAt: DateTime! +} + +type Cart { + id: ID! + userId: ID! + deliveryAddressId: ID + deliveryAddress: DeliveryAddress + items: [CartItem!]! + createdAt: DateTime! + updatedAt: DateTime! +} + type OrderItem { id: ID! productId: ID @@ -266,6 +288,7 @@ type Query { healthcheck: String! me: User myCounterpartyProfile: CounterpartyProfile + myCart: Cart! myDeliveryAddresses: [DeliveryAddress!]! myMessengerConnections: [MessengerConnection!]! myNotificationHistory(channel: MessengerType!, limit: Int = 50): [NotificationHistoryItem!]! @@ -340,6 +363,11 @@ input CreateMyDeliveryAddressInput { fiasId: String } +input UpdateCartItemQuantityInput { + productId: ID! + quantity: Float! +} + input ReadyOrderItemInput { productId: ID! quantity: Float! @@ -400,6 +428,11 @@ type Mutation { acceptInvitation(input: AcceptInvitationInput!): User! connectMessenger(input: ConnectMessengerInput!): MessengerConnection! upsertMyCounterpartyProfile(input: UpsertMyCounterpartyProfileInput!): CounterpartyProfile! + addProductToCart(productId: ID!): Cart! + updateCartItemQuantity(input: UpdateCartItemQuantityInput!): Cart! + removeCartItem(productId: ID!): Cart! + setCartDeliveryAddress(addressId: ID): Cart! + clearCart: Cart! createMyDeliveryAddress(input: CreateMyDeliveryAddressInput!): DeliveryAddress! setMyDefaultDeliveryAddress(addressId: ID!): DeliveryAddress! deleteMyDeliveryAddress(addressId: ID!): Boolean!