From a265b825d6aecd958278fccc948ebe96463e1cdc Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Fri, 10 Apr 2020 10:35:05 +0200 Subject: [PATCH 1/7] rfc proposition --- .../core/rfcs/order-getters-product-data.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/core/rfcs/order-getters-product-data.md diff --git a/packages/core/rfcs/order-getters-product-data.md b/packages/core/rfcs/order-getters-product-data.md new file mode 100644 index 000000000..bcceb5988 --- /dev/null +++ b/packages/core/rfcs/order-getters-product-data.md @@ -0,0 +1,26 @@ +# Add more data to the Order getters + +## Motivation + +In case of showing completed order items, we need a getter for its items any possibility to get additional information about each product: +- name +- quantity bought +- price +- sku + +In this RFC is also proposed price as an agnostic unit + +## Proposed interface +```TS +export interface UserOrderGetters { + getDate: (order: ORDER) => string; + getId: (order: ORDER) => string; + getStatus: (order: ORDER) => string; + getPrice: (order: ORDER) => AgnosticPrice; + getItems: (order: ORDER) => ORDER_ITEM[]; + getItemSku: (item: ORDER_ITEM) => string; + getItemName: (item: ORDER_ITEM) => string; + getItemQty: (item: ORDER_ITEM) => number; + [getterName: string]: (element: any, options?: any) => unknown; +} +``` \ No newline at end of file From 1aa96380f16264c9e183364b576c3141deafc1fb Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Tue, 14 Apr 2020 17:44:19 +0200 Subject: [PATCH 2/7] rfc proposition --- .../core/rfcs/use-user-address-factory.md | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 packages/core/rfcs/use-user-address-factory.md diff --git a/packages/core/rfcs/use-user-address-factory.md b/packages/core/rfcs/use-user-address-factory.md new file mode 100644 index 000000000..4de96e0b8 --- /dev/null +++ b/packages/core/rfcs/use-user-address-factory.md @@ -0,0 +1,128 @@ +# UseUserAddressFactory with Commerce Tools composable use case + +## Motivation + +We'd like to separate a logic for the user addresses according to single responsibility principle. It's also more agnostic approach. + +## Factory interface + +```TS +// factory schema +export interface UseUserAddressFactory { + addresses: ComputedProperty; + totalAddresses: ComputedProperty; + searchAddresses: (params?: SEARCH_PARAMS) => Promise; + addShippingAddress: (address: ADDRESS) => Promise; + addBillingAddress: (address: ADDRESS) => Promise; + getShippingAddresses: () => ADDRESS[]; + getBillingAddresses: () => ADDRESS[]; + deleteAddress: (address: ADDRESS) => Promise; + updateAddress: (address: ADDRESS) => Promise; + loading: ComputedProperty; +} +``` + +## Factory params + +```TS +// factory params schema +export type UseUserAddressFactoryParams = { + searchAddresses: (params?: SEARCH_PARAMS) => Promise; + addShippingAddress: (address: ADDRESS) => Promise; + addBillingAddress: (address: ADDRESS) => Promise; + getShippingAddresses: () => ADDRESS[]; + getBillingAddresses: () => ADDRESS[]; + deleteAddress: (address: ADDRESS) => Promise; + updateAddress: (address: ADDRESS) => Promise; +} +``` + +## User address for Commerce Tools purposes +CT GraphQL API requires from us to update user addresses through the user entity. +That means every successfull request increments user's version field. + +In this case it's required to update the user object after every (expect readonly) request. There are several ways to do this: + +1. Provide useUser composable as a dependency to the factory: +2. Any factory param that affects user address will return both updated entities: `user` and `address` +3. Mutate the user (or any other required object) directly in composable + +### 1st approach: dependency injection +That was proposed here: https://github.com/DivanteLtd/next/pull/335 but they way of providing dependency isn't still decided. + +### 2nd approach: mutate user and address +Example based on adding a new address. + +```TS +// factory params +interface UseUserAddressFactoryParams { + addAddress: (address: ADDRESS) => { updatedUser: USER, updatedAddresses: ADDRESS[] }; +} +``` + +```TS +// factory schema +interface UseUserAddressFactory { + addAddress: (address: ADDRESS) => Promise; +} +``` + +```TS +// factory usage +import { user } from 'somewhere, where is shared user for factories'; + +export function useUserAddressFactory(factoryParams) { + const addresses = ref([]); + + const addAddress = async (address) => { + const { updatedUser, updatedAddresses } = await factoryParams.addAddress(address); + + user.value = updatedUser; + addresses.value = updatedAddresses; + }; +} +``` + +### 3rd approach: mutate related entities in a composable +Example based on adding a new address. + +```TS +// factory params +interface UseUserAddressFactoryParams { + addAddress: (address: ADDRESS) => Promise; + +} +``` + +```TS +// factory schema +interface UseUserAddressFactory { + addAddress: (address: ADDRESS) => Promise; +} +``` + +```TS +// factory usage +export function useUserAddressFactory(factoryParams) { + const addresses = ref([]); + + const addAddress = async (address) => { + addresses.value = await factoryParams.addAddress(address); + }; +} +``` + +```TS +// CT factory params +import { user } from 'useUserComposable'; + +export const params: UseUserAddressFactoryParams = { + addAddress: async (address: ADDRESS) => { + const updatedUser = await apiAddAddress(address); + + user.value = updatedUser; + + return user.value.addresses; + } +} +``` From 8c4e73ac590f00cfd12e8cd153d38bf3c4f9f095 Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Wed, 15 Apr 2020 09:16:24 +0200 Subject: [PATCH 3/7] removed not related rfc --- .../core/rfcs/order-getters-product-data.md | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 packages/core/rfcs/order-getters-product-data.md diff --git a/packages/core/rfcs/order-getters-product-data.md b/packages/core/rfcs/order-getters-product-data.md deleted file mode 100644 index bcceb5988..000000000 --- a/packages/core/rfcs/order-getters-product-data.md +++ /dev/null @@ -1,26 +0,0 @@ -# Add more data to the Order getters - -## Motivation - -In case of showing completed order items, we need a getter for its items any possibility to get additional information about each product: -- name -- quantity bought -- price -- sku - -In this RFC is also proposed price as an agnostic unit - -## Proposed interface -```TS -export interface UserOrderGetters { - getDate: (order: ORDER) => string; - getId: (order: ORDER) => string; - getStatus: (order: ORDER) => string; - getPrice: (order: ORDER) => AgnosticPrice; - getItems: (order: ORDER) => ORDER_ITEM[]; - getItemSku: (item: ORDER_ITEM) => string; - getItemName: (item: ORDER_ITEM) => string; - getItemQty: (item: ORDER_ITEM) => number; - [getterName: string]: (element: any, options?: any) => unknown; -} -``` \ No newline at end of file From 6a639e9b6b2c3ef73df6c5b875b5a398b2f430a7 Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Thu, 16 Apr 2020 13:39:13 +0200 Subject: [PATCH 4/7] updated rfc --- .../core/rfcs/use-user-address-factory.md | 172 ++++++++++-------- 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/packages/core/rfcs/use-user-address-factory.md b/packages/core/rfcs/use-user-address-factory.md index 4de96e0b8..607c722a0 100644 --- a/packages/core/rfcs/use-user-address-factory.md +++ b/packages/core/rfcs/use-user-address-factory.md @@ -2,127 +2,155 @@ ## Motivation -We'd like to separate a logic for the user addresses according to single responsibility principle. It's also more agnostic approach. +We need to extend useUserAddress type to show and modify user addresses. +Also, some eCommerce platforms requires updating user entity with every address modification (for example: CommerceTools). ## Factory interface +I have actually two proposition. The one feels more agnostic while the second one is shorter. +### 1st approach (more agnostic): ```TS -// factory schema export interface UseUserAddressFactory { addresses: ComputedProperty; + shippingAddresses: ComputedProperty; + billingAddresses: ComputedProperty; totalAddresses: ComputedProperty; - searchAddresses: (params?: SEARCH_PARAMS) => Promise; + loadAddresses: (params?: SEARCH_PARAMS) => Promise; + addAddress: (address: ADDRESS) => Promise; addShippingAddress: (address: ADDRESS) => Promise; addBillingAddress: (address: ADDRESS) => Promise; - getShippingAddresses: () => ADDRESS[]; - getBillingAddresses: () => ADDRESS[]; + updateAddress: (address: ADDRESS) => Promise; deleteAddress: (address: ADDRESS) => Promise; + deleteBillingAddress: (address: ADDRESS) => Promise; + deleteShippingAddress: (address: ADDRESS) => Promise; + loading: ComputedProperty; +} +``` + +### 2nd approach (shorter): +```TS +export interface UseUserAddressFactory { + addresses: ComputedProperty; + shippingAddresses: ComputedProperty; + billingAddresses: ComputedProperty; + totalAddresses: ComputedProperty; + loadAddresses: (params?: SEARCH_PARAMS) => Promise; + addAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; updateAddress: (address: ADDRESS) => Promise; + deleteAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; loading: ComputedProperty; } ``` ## Factory params +### 1st: depending on agnostic approach ```TS // factory params schema export type UseUserAddressFactoryParams = { searchAddresses: (params?: SEARCH_PARAMS) => Promise; - addShippingAddress: (address: ADDRESS) => Promise; - addBillingAddress: (address: ADDRESS) => Promise; - getShippingAddresses: () => ADDRESS[]; getBillingAddresses: () => ADDRESS[]; - deleteAddress: (address: ADDRESS) => Promise; + getShippingAddresses: () => ADDRESS[]; + addAddress: (address: ADDRESS) => Promise; + addBillingAddress: (address: ADDRESS) => Promise; + addShippingAddress: (address: ADDRESS) => Promise; updateAddress: (address: ADDRESS) => Promise; + deleteAddress: (address: ADDRESS) => Promise; + deleteBillingAddress: (address: ADDRESS) => Promise; + deleteShippingAddress: (address: ADDRESS) => Promise; } ``` -## User address for Commerce Tools purposes -CT GraphQL API requires from us to update user addresses through the user entity. -That means every successfull request increments user's version field. - -In this case it's required to update the user object after every (expect readonly) request. There are several ways to do this: - -1. Provide useUser composable as a dependency to the factory: -2. Any factory param that affects user address will return both updated entities: `user` and `address` -3. Mutate the user (or any other required object) directly in composable - -### 1st approach: dependency injection -That was proposed here: https://github.com/DivanteLtd/next/pull/335 but they way of providing dependency isn't still decided. - -### 2nd approach: mutate user and address -Example based on adding a new address. - +### 2nd: shorter one ```TS -// factory params -interface UseUserAddressFactoryParams { - addAddress: (address: ADDRESS) => { updatedUser: USER, updatedAddresses: ADDRESS[] }; +// factory params schema +export type UseUserAddressFactoryParams = { + searchAddresses: (params?: SEARCH_PARAMS) => Promise; + getByType: (type: ADDRESS_TYPE) => ADDRESS[]; + addAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; + updateAddress: (address: ADDRESS) => Promise; + deleteAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; } ``` +## Other changes requirements: +We need to add a possibility to update a user ```TS -// factory schema -interface UseUserAddressFactory { - addAddress: (address: ADDRESS) => Promise; +// FACTORY INTERFACE +export interface UseUser +< + USER, + UPDATE_USER_PARAMS +> { + // ...leave all the stuff as they are now + + // needed to add this: + setUser: (newUser: USER) => void; + useUser: () => USER; } ``` ```TS -// factory usage -import { user } from 'somewhere, where is shared user for factories'; - -export function useUserAddressFactory(factoryParams) { - const addresses = ref([]); - - const addAddress = async (address) => { - const { updatedUser, updatedAddresses } = await factoryParams.addAddress(address); - - user.value = updatedUser; - addresses.value = updatedAddresses; +// FACTORY IMPLEMENTATION +export function useUserFactory( + factoryParams: UseUserFactoryParams +) { + // ...leave all the stuff as they are now + + // needed to add this: + const setUser = (newUser: USER) => { + user.value = newUser; }; + const useUser = () => user; + + return { + user: computed(() => user.value), + setUser, // these both are required to be added + useUser, // + updateUser, + register, + login, + logout, + isAuthenticated, + changePassword, + refreshUser, + loading: computed(() => loading.value) + }; } ``` -### 3rd approach: mutate related entities in a composable -Example based on adding a new address. - -```TS -// factory params -interface UseUserAddressFactoryParams { - addAddress: (address: ADDRESS) => Promise; +## Commerce Tools Integration +In order to integrate CT we need a user instance to update it. It's required, because addresses are being updated through user update endpoint. -} -``` +Below example when adding an address +### Factory params ```TS -// factory schema -interface UseUserAddressFactory { - addAddress: (address: ADDRESS) => Promise; -} -``` +import { setUser } from './useUser'; -```TS -// factory usage -export function useUserAddressFactory(factoryParams) { - const addresses = ref([]); +const factoryParams = { + addAddress: async (address) => { + const { user } = await apiAddAddress(address); - const addAddress = async (address) => { - addresses.value = await factoryParams.addAddress(address); - }; -} + setUser(user); + + return user.addresses; + } +}; ``` +### Factory content ```TS -// CT factory params -import { user } from 'useUserComposable'; +const useUserAddressFactory = () => { + const addresses: ref([]); + const loading: ref(false); -export const params: UseUserAddressFactoryParams = { - addAddress: async (address: ADDRESS) => { - const updatedUser = await apiAddAddress(address); + const addAddress: async (address) => { + loading.value = true; - user.value = updatedUser; + addresses.value = await factoryParams.addAddress(address); - return user.value.addresses; + loading.value = false; } -} +}; ``` From b9c2d190b308fdeb8c550177d0cb60c8a369d7d9 Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Thu, 16 Apr 2020 13:54:30 +0200 Subject: [PATCH 5/7] removed useUser from useUSerFactory --- packages/core/rfcs/use-user-address-factory.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/core/rfcs/use-user-address-factory.md b/packages/core/rfcs/use-user-address-factory.md index 607c722a0..523ac5ab0 100644 --- a/packages/core/rfcs/use-user-address-factory.md +++ b/packages/core/rfcs/use-user-address-factory.md @@ -86,7 +86,6 @@ export interface UseUser // needed to add this: setUser: (newUser: USER) => void; - useUser: () => USER; } ``` @@ -101,12 +100,10 @@ export function useUserFactory { user.value = newUser; }; - const useUser = () => user; return { user: computed(() => user.value), - setUser, // these both are required to be added - useUser, // + setUser, // required to be added updateUser, register, login, From 55cdac06816f60320c49165e588186133107e114 Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Fri, 17 Apr 2020 08:44:13 +0200 Subject: [PATCH 6/7] updated rfc according to decisions made --- .../core/rfcs/use-user-address-factory.md | 59 +++---------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/packages/core/rfcs/use-user-address-factory.md b/packages/core/rfcs/use-user-address-factory.md index 523ac5ab0..c22ffd394 100644 --- a/packages/core/rfcs/use-user-address-factory.md +++ b/packages/core/rfcs/use-user-address-factory.md @@ -6,70 +6,29 @@ We need to extend useUserAddress type to show and modify user addresses. Also, some eCommerce platforms requires updating user entity with every address modification (for example: CommerceTools). ## Factory interface -I have actually two proposition. The one feels more agnostic while the second one is shorter. - -### 1st approach (more agnostic): -```TS -export interface UseUserAddressFactory { - addresses: ComputedProperty; - shippingAddresses: ComputedProperty; - billingAddresses: ComputedProperty; - totalAddresses: ComputedProperty; - loadAddresses: (params?: SEARCH_PARAMS) => Promise; - addAddress: (address: ADDRESS) => Promise; - addShippingAddress: (address: ADDRESS) => Promise; - addBillingAddress: (address: ADDRESS) => Promise; - updateAddress: (address: ADDRESS) => Promise; - deleteAddress: (address: ADDRESS) => Promise; - deleteBillingAddress: (address: ADDRESS) => Promise; - deleteShippingAddress: (address: ADDRESS) => Promise; - loading: ComputedProperty; -} -``` - -### 2nd approach (shorter): ```TS -export interface UseUserAddressFactory { +export interface UseUserAddressFactory { addresses: ComputedProperty; shippingAddresses: ComputedProperty; billingAddresses: ComputedProperty; - totalAddresses: ComputedProperty; loadAddresses: (params?: SEARCH_PARAMS) => Promise; - addAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; - updateAddress: (address: ADDRESS) => Promise; - deleteAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; + addAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; + updateAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; + deleteAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; loading: ComputedProperty; } ``` ## Factory params - -### 1st: depending on agnostic approach ```TS // factory params schema -export type UseUserAddressFactoryParams = { - searchAddresses: (params?: SEARCH_PARAMS) => Promise; +export type UseUserAddressFactoryParams = { + loadAddresses: (params?: SEARCH_PARAMS) => Promise; getBillingAddresses: () => ADDRESS[]; getShippingAddresses: () => ADDRESS[]; - addAddress: (address: ADDRESS) => Promise; - addBillingAddress: (address: ADDRESS) => Promise; - addShippingAddress: (address: ADDRESS) => Promise; - updateAddress: (address: ADDRESS) => Promise; - deleteAddress: (address: ADDRESS) => Promise; - deleteBillingAddress: (address: ADDRESS) => Promise; - deleteShippingAddress: (address: ADDRESS) => Promise; -} -``` - -### 2nd: shorter one -```TS -// factory params schema -export type UseUserAddressFactoryParams = { - searchAddresses: (params?: SEARCH_PARAMS) => Promise; - getByType: (type: ADDRESS_TYPE) => ADDRESS[]; - addAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; - updateAddress: (address: ADDRESS) => Promise; - deleteAddress: (address: ADDRESS, type?: ADDRESS_TYPE) => Promise; + addAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; + updateAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; + deleteAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; } ``` From f9e28cd9647c2a2b98d3b5e2d2306bd1f3f21340 Mon Sep 17 00:00:00 2001 From: Marcin Drwiega Date: Fri, 17 Apr 2020 15:56:01 +0200 Subject: [PATCH 7/7] updated rfc according to decision making meeting --- .../core/rfcs/use-user-address-factory.md | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/core/rfcs/use-user-address-factory.md b/packages/core/rfcs/use-user-address-factory.md index c22ffd394..8a9ff680f 100644 --- a/packages/core/rfcs/use-user-address-factory.md +++ b/packages/core/rfcs/use-user-address-factory.md @@ -5,9 +5,9 @@ We need to extend useUserAddress type to show and modify user addresses. Also, some eCommerce platforms requires updating user entity with every address modification (for example: CommerceTools). -## Factory interface +## Composable interface ```TS -export interface UseUserAddressFactory { +export interface UseUserAddress { addresses: ComputedProperty; shippingAddresses: ComputedProperty; billingAddresses: ComputedProperty; @@ -19,13 +19,13 @@ export interface UseUserAddressFactory = { loadAddresses: (params?: SEARCH_PARAMS) => Promise; - getBillingAddresses: () => ADDRESS[]; - getShippingAddresses: () => ADDRESS[]; + getBillingAddresses: (addresses: ADDRESS[]) => ADDRESS[]; + getShippingAddresses: (addresses: ADDRESS[]) => ADDRESS[]; addAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; updateAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; deleteAddress: (address: ADDRESS, options?: ADDRESS_OPTIONS) => Promise; @@ -78,7 +78,7 @@ export function useUserFactory { +export function useUserAddressFactory = (factoryParams) => { const addresses: ref([]); const loading: ref(false); - const addAddress: async (address) => { - loading.value = true; + return function useUserAddress(): UseUserAddress { + const addAddress: async (address) => { + loading.value = true; + addresses.value = await factoryParams.addAddress(address); + loading.value = false; + } - addresses.value = await factoryParams.addAddress(address); + // and other methods - loading.value = false; + return { + addresses: computed(() => addresses.value); + addAddress, + // ...And other stuff mentioned in interfaces section + } } }; ```