import { syncRefs } from "@vueuse/core"; import { computed, ref } from "vue"; import type { ComputedRef, Ref } from "vue"; import { useCart, useContext, useInternationalization, useSessionContext, useShopwareContext, } from "#imports"; import type { Schemas, operations } from "#shopware"; export type UseUserReturn = { /** * Logs-in user with given credentials * @param params - username and password * * @see https://github.com/shopware/frontends/issues/112 if login fails due to missing context token */ login(params: { username: string; password: string }): Promise; /** * Registers the user for given credentials * @param params {@link CustomerRegistrationParams} * @returns {@link Customer} object on success */ register( params: Omit< operations["register post /account/register"]["body"], "storefrontUrl" >, ): Promise; /** * Whole {@link Customer} object */ user: ComputedRef; /** * Indicates if the user is logged in */ isLoggedIn: ComputedRef; /** * Indicates if the user is logged in as a customer (not a guest) */ isCustomerSession: ComputedRef; /** * Indicates if the user is logged in as a guest */ isGuestSession: ComputedRef; /** * {@link Country} of the user */ country: Ref; /** * {@link Salutation} of the user */ salutation: Ref; /** * Default billing address id */ defaultBillingAddressId: ComputedRef; /** * Default shipping address id */ defaultShippingAddressId: ComputedRef; /** * Fetches the user data from the API */ refreshUser(params?: Schemas["Criteria"]): Promise; /** * Logs out the user */ logout(): Promise< operations["logoutCustomer post /account/logout"]["response"] >; /** * Loads the {@link Country} of the user */ loadCountry( countryId: string, ): Promise; /** * Loads the {@link Salutation} for given id */ loadSalutation( salutationId: string, ): Promise; /** * Updates the user profile data * @param personals {@link RequestParameters<'changeProfile'>} * @returns */ updatePersonalInfo( personals: operations["changeProfile post /account/change-profile"]["body"], ): Promise; /** * Updates the user email * @param updateEmailData - {@link RequestParameters<'changeEmail'>} * @returns */ updateEmail( updateEmailData: operations["changeEmail post /account/change-email"]["body"], ): Promise; /** * Sets the default payment method for given id * @param paymentMethodId * @returns */ setDefaultPaymentMethod(paymentMethodId: string): Promise; /** * Default payment method for the user */ userDefaultPaymentMethod: ComputedRef< Schemas["PaymentMethod"]["translated"] | null >; /** * Default billing address for the user */ userDefaultBillingAddress: ComputedRef; /** * Default shipping address for the user */ userDefaultShippingAddress: ComputedRef; }; /** * Composable for user management. * @public * @category Customer & Account */ export function useUser(): UseUserReturn { const { apiClient } = useShopwareContext(); const { userFromContext, refreshSessionContext } = useSessionContext(); const _user = useContext("customer"); syncRefs(userFromContext, _user, { immediate: true, }); const { getStorefrontUrl } = useInternationalization(); const { refreshCart } = useCart(); const userDefaultPaymentMethod = computed( () => user.value?.defaultPaymentMethod?.translated || null, ); const userDefaultBillingAddress = computed( () => user.value?.defaultBillingAddress || null, ); const userDefaultShippingAddress = computed( () => user.value?.defaultShippingAddress || null, ); const country: Ref = ref(null); const salutation: Ref = ref(null); const user = computed(() => _user.value); async function login({ username, password, }: { username: string; password: string; }): Promise { await apiClient.invoke("loginCustomer post /account/login", { body: { username, password, }, }); await refreshSessionContext(); refreshCart(); } async function register( params: Omit< operations["register post /account/register"]["body"], "storefrontUrl" >, ): Promise { const { data } = await apiClient.invoke("register post /account/register", { body: { ...(params as operations["register post /account/register"]["body"]), storefrontUrl: getStorefrontUrl(), }, }); // Update the user data in the context if the user is active and not using double opt-in registration set in the Shopware Admin if (data.active && !data.doubleOptInRegistration) { _user.value = data; } await refreshSessionContext(); return data; } async function logout(): Promise< operations["logoutCustomer post /account/logout"]["response"] > { const response = await apiClient.invoke( "logoutCustomer post /account/logout", ); await refreshSessionContext(); refreshCart(); return response.data; } async function refreshUser( params: Schemas["Criteria"] = {}, ): Promise { try { const response = await apiClient.invoke( "readCustomer post /account/customer", { body: params }, ); _user.value = response.data; return response.data; } catch (e) { _user.value = undefined; throw e; } } async function loadCountry( countryId: string, ): Promise { const countries = await apiClient.invoke("readCountry post /country", { body: { filter: [ { field: "id", type: "equals", value: countryId, }, ], }, }); country.value = countries.data.elements?.[0] ?? null; return countries.data; } async function loadSalutation( salutationId: string, ): Promise { const salutations = await apiClient.invoke( "readSalutation post /salutation", { body: { filter: [ { field: "id", type: "equals", value: salutationId, }, ], }, }, ); salutation.value = salutations.data.elements?.[0] ?? null; return salutations.data; } async function updatePersonalInfo( personals: operations["changeProfile post /account/change-profile"]["body"], ): Promise { await apiClient.invoke("changeProfile post /account/change-profile", { body: personals, }); } async function updateEmail( updateEmailData: operations["changeEmail post /account/change-email"]["body"], ): Promise { await apiClient.invoke("changeEmail post /account/change-email", { body: updateEmailData, }); } async function setDefaultPaymentMethod( paymentMethodId: string, ): Promise { await apiClient.invoke( "changePaymentMethod post /account/change-payment-method/{paymentMethodId}", { pathParams: { paymentMethodId }, }, ); } const defaultBillingAddressId = computed( () => user.value?.defaultBillingAddressId || null, ); const defaultShippingAddressId = computed( () => user.value?.defaultShippingAddressId || null, ); const isLoggedIn = computed( () => !!user.value?.id && !!user.value.active && !user.value.guest, ); const isCustomerSession = computed( () => !!user.value?.id && !user.value.guest, ); const isGuestSession = computed(() => !!user.value?.guest); return { login, register, user, isLoggedIn, isCustomerSession, isGuestSession, refreshUser, logout, updateEmail, updatePersonalInfo, setDefaultPaymentMethod, loadSalutation, salutation, loadCountry, country, defaultBillingAddressId, defaultShippingAddressId, userDefaultPaymentMethod, userDefaultBillingAddress, userDefaultShippingAddress, }; }