Stage M8
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { HttpClient, type HttpClientOptions } from './http-client';
|
||||
import { createAccountResource, type AccountResource } from './resources/account';
|
||||
import { createAdminResource, type AdminResource } from './resources/admin';
|
||||
import { createAuthResource, type AuthResource } from './resources/auth';
|
||||
import { createCatalogResource, type CatalogResource } from './resources/catalog';
|
||||
@@ -45,6 +46,7 @@ export interface ApiClient {
|
||||
readonly promotionsAdmin: PromotionsAdminResource;
|
||||
readonly reviews: ReviewsResource;
|
||||
readonly reviewsAdmin: ReviewsAdminResource;
|
||||
readonly account: AccountResource;
|
||||
readonly content: ContentResource;
|
||||
readonly contentAdmin: ContentAdminResource;
|
||||
}
|
||||
@@ -64,6 +66,7 @@ export function createApiClient(options: HttpClientOptions): ApiClient {
|
||||
promotionsAdmin: createPromotionsAdminResource(http),
|
||||
reviews: createReviewsResource(http),
|
||||
reviewsAdmin: createReviewsAdminResource(http),
|
||||
account: createAccountResource(http),
|
||||
content: createContentResource(http),
|
||||
contentAdmin: createContentAdminResource(http),
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ export { HttpClient } from './http-client';
|
||||
export type { HttpClientOptions, RequestOptions } from './http-client';
|
||||
export { createApiClient } from './create-client';
|
||||
export type { CatalogResource, ProductListQuery } from './resources/catalog';
|
||||
export type { AuthResource, LoginCredentials } from './resources/auth';
|
||||
export type { AuthResource, LoginCredentials, RegisterPayload } from './resources/auth';
|
||||
export type {
|
||||
AdminResource,
|
||||
CreateUserPayload,
|
||||
@@ -58,4 +58,5 @@ export type {
|
||||
ContentTranslationPayload,
|
||||
PostListParams,
|
||||
} from './resources/content';
|
||||
export type { AccountResource, AddressPayload, ProfilePayload } from './resources/account';
|
||||
export type { ApiClient } from './create-client';
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import type {
|
||||
CustomerAddress,
|
||||
CustomerProfile,
|
||||
OffsetPaginated,
|
||||
Order,
|
||||
OrderListItem,
|
||||
} from '@sport/types';
|
||||
|
||||
import type { HttpClient } from '../http-client';
|
||||
|
||||
export interface ProfilePayload {
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
phone?: string | null;
|
||||
acceptsMarketing?: boolean;
|
||||
dateOfBirth?: string | null;
|
||||
}
|
||||
|
||||
export interface AddressPayload {
|
||||
fullName: string;
|
||||
phone: string;
|
||||
line1: string;
|
||||
line2?: string | null;
|
||||
ward?: string | null;
|
||||
district?: string | null;
|
||||
province: string;
|
||||
countryCode?: string;
|
||||
postalCode?: string | null;
|
||||
isDefaultShipping?: boolean;
|
||||
isDefaultBilling?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signed-in shopper's own account.
|
||||
*
|
||||
* Every method is implicitly scoped to the bearer token — there is no customer
|
||||
* id parameter anywhere, because the server takes it from the session.
|
||||
*/
|
||||
export interface AccountResource {
|
||||
getProfile(): Promise<CustomerProfile>;
|
||||
updateProfile(payload: ProfilePayload): Promise<CustomerProfile>;
|
||||
|
||||
listAddresses(): Promise<CustomerAddress[]>;
|
||||
createAddress(payload: AddressPayload): Promise<CustomerAddress>;
|
||||
updateAddress(id: string, payload: AddressPayload): Promise<CustomerAddress>;
|
||||
deleteAddress(id: string): Promise<void>;
|
||||
|
||||
listOrders(params?: { page?: number; perPage?: number }): Promise<OffsetPaginated<OrderListItem>>;
|
||||
getOrder(id: string): Promise<Order>;
|
||||
|
||||
listWishlist(): Promise<string[]>;
|
||||
addToWishlist(productId: string): Promise<{ ok: true }>;
|
||||
removeFromWishlist(productId: string): Promise<{ ok: true }>;
|
||||
}
|
||||
|
||||
export function createAccountResource(http: HttpClient): AccountResource {
|
||||
// Never cached. Everything here is one person's own data, and a stale
|
||||
// address book is one that shows a home they moved out of.
|
||||
const uncached = { cache: 'no-store' } as const;
|
||||
|
||||
return {
|
||||
getProfile: () => http.get<CustomerProfile>('/account/profile', uncached),
|
||||
updateProfile: (payload) => http.patch<CustomerProfile>('/account/profile', payload, uncached),
|
||||
|
||||
listAddresses: () => http.get<CustomerAddress[]>('/account/addresses', uncached),
|
||||
createAddress: (payload) => http.post<CustomerAddress>('/account/addresses', payload, uncached),
|
||||
updateAddress: (id, payload) =>
|
||||
http.patch<CustomerAddress>(
|
||||
`/account/addresses/${encodeURIComponent(id)}`,
|
||||
payload,
|
||||
uncached,
|
||||
),
|
||||
deleteAddress: (id) =>
|
||||
http.delete<void>(`/account/addresses/${encodeURIComponent(id)}`, uncached),
|
||||
|
||||
listOrders: (params = {}) =>
|
||||
http.get<OffsetPaginated<OrderListItem>>('/account/orders', {
|
||||
...uncached,
|
||||
query: { ...params },
|
||||
}),
|
||||
getOrder: (id) => http.get<Order>(`/account/orders/${encodeURIComponent(id)}`, uncached),
|
||||
|
||||
listWishlist: () => http.get<string[]>('/account/wishlist', uncached),
|
||||
addToWishlist: (productId) =>
|
||||
http.post<{ ok: true }>('/account/wishlist', { productId }, uncached),
|
||||
removeFromWishlist: (productId) =>
|
||||
http.delete<{ ok: true }>(`/account/wishlist/${encodeURIComponent(productId)}`, uncached),
|
||||
};
|
||||
}
|
||||
@@ -12,8 +12,19 @@ export interface LoginCredentials {
|
||||
* cookies for separate audiences. Exposing them as one method with a flag would
|
||||
* make it far too easy to point a customer credential at the admin surface.
|
||||
*/
|
||||
export interface RegisterPayload {
|
||||
email: string;
|
||||
password: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
phone?: string;
|
||||
acceptsMarketing?: boolean;
|
||||
}
|
||||
|
||||
export interface AuthResource {
|
||||
login(credentials: LoginCredentials): Promise<LoginResult>;
|
||||
/** Storefront only — there is deliberately no way to self-register staff. */
|
||||
register(payload: RegisterPayload): Promise<LoginResult>;
|
||||
adminLogin(credentials: LoginCredentials): Promise<LoginResult>;
|
||||
refresh(): Promise<RefreshResult>;
|
||||
adminRefresh(): Promise<RefreshResult>;
|
||||
@@ -40,6 +51,7 @@ export function createAuthResource(http: HttpClient): AuthResource {
|
||||
|
||||
return {
|
||||
login: (credentials) => http.post<LoginResult>('/auth/login', credentials, uncached),
|
||||
register: (payload) => http.post<LoginResult>('/auth/register', payload, uncached),
|
||||
adminLogin: (credentials) => http.post<LoginResult>('/auth/admin/login', credentials, uncached),
|
||||
refresh: () => http.post<RefreshResult>('/auth/refresh', undefined, uncached),
|
||||
adminRefresh: () => http.post<RefreshResult>('/auth/admin/refresh', undefined, uncached),
|
||||
|
||||
@@ -18,6 +18,7 @@ import type { HttpClient, RequestOptions } from '../http-client';
|
||||
* for callers, never the enforcement point.
|
||||
*/
|
||||
export interface ProductListQuery {
|
||||
ids?: string[];
|
||||
q?: string;
|
||||
categorySlug?: string;
|
||||
collectionSlug?: string;
|
||||
|
||||
Reference in New Issue
Block a user