corvée(lint) applique des suggestions de lint Oxlint
This commit is contained in:
parent
c66cf7faba
commit
498ae877a1
6 changed files with 64 additions and 36 deletions
|
|
@ -1,14 +1,16 @@
|
||||||
import { Console, Context, Effect, Layer, Match, pipe, Schedule, Schema, SchemaIssue } from "effect";
|
import { Console, Context, Effect, Layer, Match, pipe, Schedule, Schema, SchemaIssue } from "effect";
|
||||||
import { SchemaError } from "effect/Schema";
|
import type { SchemaError } from "effect/Schema";
|
||||||
|
import type {
|
||||||
|
HttpClientError,
|
||||||
|
} from "effect/unstable/http";
|
||||||
import {
|
import {
|
||||||
FetchHttpClient,
|
FetchHttpClient,
|
||||||
HttpClient,
|
HttpClient,
|
||||||
HttpClientError,
|
|
||||||
HttpClientRequest,
|
HttpClientRequest,
|
||||||
HttpClientResponse,
|
HttpClientResponse,
|
||||||
} from "effect/unstable/http";
|
} from "effect/unstable/http";
|
||||||
import { HttpClientErrorSchema } from "effect/unstable/http/HttpClientError";
|
import { HttpClientErrorSchema } from "effect/unstable/http/HttpClientError";
|
||||||
import type { CartProduct } from "../schemas/api.ts";
|
import type { CartProduct, GetProducts } from "../schemas/api.ts";
|
||||||
import { WooCommerceCart } from "../schemas/cart.ts";
|
import { WooCommerceCart } from "../schemas/cart.ts";
|
||||||
|
|
||||||
/** Le nombre maximal d'essais pour une Requête. */
|
/** Le nombre maximal d'essais pour une Requête. */
|
||||||
|
|
@ -16,20 +18,21 @@ const MAX_RETRIES = 3;
|
||||||
/** Le temps d'attente avant de réessayer une Requête. */
|
/** Le temps d'attente avant de réessayer une Requête. */
|
||||||
const RETRY_WAIT_TIME = "1 seconds";
|
const RETRY_WAIT_TIME = "1 seconds";
|
||||||
|
|
||||||
|
type APIError = APIRequestError | APIResponseError;
|
||||||
|
|
||||||
|
type APIResponse<T> = T | WooCommerceError;
|
||||||
|
|
||||||
/** Décrit une Erreur survenue au traitement d'une `Request`. */
|
/** Décrit une Erreur survenue au traitement d'une `Request`. */
|
||||||
class APIRequestError extends Schema.TaggedErrorClass<APIRequestError>()("APIRequestError", {
|
class APIRequestError extends Schema.TaggedErrorClass<APIRequestError>()("APIRequestError", {
|
||||||
message: Schema.String,
|
|
||||||
cause: Schema.Union([Schema.Defect, HttpClientErrorSchema]),
|
cause: Schema.Union([Schema.Defect, HttpClientErrorSchema]),
|
||||||
|
message: Schema.String,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
/** Décrit une Erreur survenue au traitement d'une `Response`. */
|
/** Décrit une Erreur survenue au traitement d'une `Response`. */
|
||||||
class APIResponseError extends Schema.TaggedErrorClass<APIResponseError>()("APIResponseError", {
|
class APIResponseError extends Schema.TaggedErrorClass<APIResponseError>()("APIResponseError", {
|
||||||
message: Schema.String,
|
|
||||||
cause: Schema.Union([Schema.Defect, HttpClientErrorSchema]),
|
cause: Schema.Union([Schema.Defect, HttpClientErrorSchema]),
|
||||||
|
message: Schema.String,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
type APIError = APIRequestError | APIResponseError;
|
|
||||||
|
|
||||||
class WooCommerceErrorBody extends Schema.Class<WooCommerceErrorBody>("WooCommerceErrorBody")({
|
class WooCommerceErrorBody extends Schema.Class<WooCommerceErrorBody>("WooCommerceErrorBody")({
|
||||||
code: Schema.String,
|
code: Schema.String,
|
||||||
data: Schema.Struct({
|
data: Schema.Struct({
|
||||||
|
|
@ -37,13 +40,12 @@ class WooCommerceErrorBody extends Schema.Class<WooCommerceErrorBody>("WooCommer
|
||||||
}),
|
}),
|
||||||
message: Schema.String,
|
message: Schema.String,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
class WooCommerceError extends Schema.Class<WooCommerceError>("WooCommerceError")({
|
class WooCommerceError extends Schema.Class<WooCommerceError>("WooCommerceError")({
|
||||||
body: WooCommerceErrorBody,
|
body: WooCommerceErrorBody,
|
||||||
status: Schema.Number,
|
status: Schema.Number,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
type APIResponse<T> = T | WooCommerceError;
|
|
||||||
|
|
||||||
/** Client `fetch` contenant les options et en-têtes de Requêtes pré-renseignées. */
|
/** Client `fetch` contenant les options et en-têtes de Requêtes pré-renseignées. */
|
||||||
const APIFetchClient = FetchHttpClient.layer.pipe(
|
const APIFetchClient = FetchHttpClient.layer.pipe(
|
||||||
Layer.provide(
|
Layer.provide(
|
||||||
|
|
@ -81,22 +83,22 @@ class APIClient extends Context.Service<APIClient>()("haikuatelier.fr/APIClient"
|
||||||
const matchAPIError = (error: HttpClientError.HttpClientError | SchemaError): APIError => {
|
const matchAPIError = (error: HttpClientError.HttpClientError | SchemaError): APIError => {
|
||||||
if (error._tag === "SchemaError") {
|
if (error._tag === "SchemaError") {
|
||||||
return new APIRequestError({
|
return new APIRequestError({
|
||||||
message: `Erreur lors du parsage du corps de la Requête :${SchemaIssue.makeFormatterDefault()(error.issue)}`,
|
|
||||||
cause: error,
|
cause: error,
|
||||||
|
message: `Erreur lors du parsage du corps de la Requête :${SchemaIssue.makeFormatterDefault()(error.issue)}`,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Match.typeTags<HttpClientError.HttpClientErrorReason, APIError>()({
|
return Match.typeTags<HttpClientError.HttpClientErrorReason, APIError>()({
|
||||||
|
DecodeError: cause => new APIResponseError({ cause, message: "Le corps de la Réponse ne peut être lu" }),
|
||||||
|
EmptyBodyError: cause => new APIResponseError({ cause, message: "Un corps vide ne peut être lu" }),
|
||||||
|
EncodeError: cause => new APIRequestError({ cause, message: "Le corps de la Requête ne peut être lu" }),
|
||||||
|
InvalidUrlError: cause => new APIRequestError({ cause, message: "L'URL de la Requête n'est pas valide" }),
|
||||||
|
StatusCodeError: cause =>
|
||||||
|
new APIResponseError({ cause, message: "Le code HTTP de la Réponse correspond à un échec" }),
|
||||||
TransportError: (cause): APIError =>
|
TransportError: (cause): APIError =>
|
||||||
new APIRequestError({
|
new APIRequestError({
|
||||||
cause,
|
cause,
|
||||||
message: "Un problème réseau empêche l'exécution de la Requête",
|
message: "Un problème réseau empêche l'exécution de la Requête",
|
||||||
}),
|
}),
|
||||||
EncodeError: cause => new APIRequestError({ cause, message: "Le corps de la Requête ne peut être lu" }),
|
|
||||||
InvalidUrlError: cause => new APIRequestError({ cause, message: "L'URL de la Requête n'est pas valide" }),
|
|
||||||
StatusCodeError: cause =>
|
|
||||||
new APIResponseError({ cause, message: "Le code HTTP de la Réponse correspond à un échec" }),
|
|
||||||
DecodeError: cause => new APIResponseError({ cause, message: "Le corps de la Réponse ne peut être lu" }),
|
|
||||||
EmptyBodyError: cause => new APIResponseError({ cause, message: "Un corps vide ne peut être lu" }),
|
|
||||||
})(error.reason);
|
})(error.reason);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -109,7 +111,7 @@ class APIClient extends Context.Service<APIClient>()("haikuatelier.fr/APIClient"
|
||||||
return yield* Effect.succeed(error);
|
return yield* Effect.succeed(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
const AddProductToCart = Effect.fn("AppClient.AddProductToCart")(
|
const AddProductToCart = Effect.fn("APIClient.AddProductToCart")(
|
||||||
function*(nonce: string, productToAdd: CartProduct): Effect.fn.Return<APIResponse<WooCommerceCart>, APIError> {
|
function*(nonce: string, productToAdd: CartProduct): Effect.fn.Return<APIResponse<WooCommerceCart>, APIError> {
|
||||||
const request = pipe(
|
const request = pipe(
|
||||||
HttpClientRequest.post(`/wp-json/wc/store/cart/add-item`),
|
HttpClientRequest.post(`/wp-json/wc/store/cart/add-item`),
|
||||||
|
|
@ -132,7 +134,28 @@ class APIClient extends Context.Service<APIClient>()("haikuatelier.fr/APIClient"
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return { AddProductToCart };
|
const GetProducts = Effect.fn("APIClient.GetProducts")(
|
||||||
|
function*(nonce: string, authString: string, queryParams: GetProducts) {
|
||||||
|
const request = pipe(
|
||||||
|
HttpClientRequest.get(`/wp-json/wc/store/products`),
|
||||||
|
HttpClientRequest.setHeader("Nonce", nonce),
|
||||||
|
HttpClientRequest.bearerToken(authString),
|
||||||
|
// Le corps de la Requête a été validée en amont, on peut utiliser Unsafe.
|
||||||
|
HttpClientRequest.setUrlParams(queryParams),
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = yield* pipe(
|
||||||
|
haikuHTTPClient.execute(request),
|
||||||
|
Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Unknown)),
|
||||||
|
Effect.mapError(error => matchAPIError(error)),
|
||||||
|
Effect.tapError(error => printErrorAsSuccinctMessage(error)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return { AddProductToCart, GetProducts };
|
||||||
}),
|
}),
|
||||||
}) {
|
}) {
|
||||||
static readonly Live = Layer.effect(this, this.make).pipe(Layer.provide(APIFetchClient));
|
static readonly Live = Layer.effect(this, this.make).pipe(Layer.provide(APIFetchClient));
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ const getAllSelectorFromParent =
|
||||||
pipe(
|
pipe(
|
||||||
parent.querySelectorAll<E>(selector),
|
parent.querySelectorAll<E>(selector),
|
||||||
// Convertis NodeListOf en Array.
|
// Convertis NodeListOf en Array.
|
||||||
(xs: NodeListOf<E>) => Array.from<E>(xs),
|
(xs: NodeListOf<E>) => [...xs],
|
||||||
(xs: Array<E>) => Option.liftPredicate(FxArray.isReadonlyArrayNonEmpty)(xs),
|
(xs: Array<E>) => Option.liftPredicate(FxArray.isReadonlyArrayNonEmpty)(xs),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Effect } from "effect";
|
||||||
|
import { ATTRIBUT_CHARGEMENT, ATTRIBUT_DESACTIVE } from "../../scripts/constantes/dom.ts";
|
||||||
|
|
||||||
|
const setLoadingState = Effect.fn("setLoadingState")(function*(element: HTMLElement, isLoading: boolean) {
|
||||||
|
element.toggleAttribute(ATTRIBUT_DESACTIVE, isLoading);
|
||||||
|
element.toggleAttribute(ATTRIBUT_CHARGEMENT, isLoading);
|
||||||
|
});
|
||||||
|
|
||||||
|
export { setLoadingState };
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import { Context, Effect, flow, Layer, pipe, Schedule, Schema } from "effect";
|
import { Context, Effect, flow, Layer, pipe, Schedule, Schema } from "effect";
|
||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
|
||||||
import { HttpClientError } from "effect/unstable/http/HttpClientError";
|
import type { HttpClientError } from "effect/unstable/http/HttpClientError";
|
||||||
|
|
||||||
class Todo extends Schema.Class<Todo>("Todo")({
|
|
||||||
userId: Schema.Number,
|
|
||||||
id: Schema.Number,
|
|
||||||
title: Schema.String,
|
|
||||||
completed: Schema.Boolean,
|
|
||||||
}) {}
|
|
||||||
|
|
||||||
class FetchClientError extends Schema.TaggedErrorClass<FetchClientError>()("FetchClientError", {
|
class FetchClientError extends Schema.TaggedErrorClass<FetchClientError>()("FetchClientError", {
|
||||||
cause: Schema.Defect,
|
cause: Schema.Defect,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
|
class Todo extends Schema.Class<Todo>("Todo")({
|
||||||
|
completed: Schema.Boolean,
|
||||||
|
id: Schema.Number,
|
||||||
|
title: Schema.String,
|
||||||
|
userId: Schema.Number,
|
||||||
|
}) {}
|
||||||
|
|
||||||
class FetchClientExample extends Context.Service<FetchClientExample, {
|
class FetchClientExample extends Context.Service<FetchClientExample, {
|
||||||
readonly allTodos: Effect.Effect<ReadonlyArray<Todo>, FetchClientError>;
|
readonly allTodos: Effect.Effect<ReadonlyArray<Todo>, FetchClientError>;
|
||||||
createTodo(todo: Omit<Todo, "id">): Effect.Effect<Todo, FetchClientError>;
|
createTodo(todo: Omit<Todo, "id">): Effect.Effect<Todo, FetchClientError>;
|
||||||
|
|
@ -75,8 +75,8 @@ class FetchClientExample extends Context.Service<FetchClientExample, {
|
||||||
|
|
||||||
return FetchClientExample.of({
|
return FetchClientExample.of({
|
||||||
allTodos,
|
allTodos,
|
||||||
getTodo,
|
|
||||||
createTodo,
|
createTodo,
|
||||||
|
getTodo,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
).pipe(
|
).pipe(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
// oxlint-disable typescript/dot-notation
|
||||||
import type { SchemaError } from "effect/Schema";
|
import type { SchemaError } from "effect/Schema";
|
||||||
|
|
||||||
// oxlint-disable typescript/dot-notation
|
|
||||||
import {
|
import {
|
||||||
Array as FxArray,
|
Array as FxArray,
|
||||||
Console,
|
Console,
|
||||||
|
|
@ -21,6 +21,7 @@ import type { APIError } from "../../scripts-effect/lib/api.ts";
|
||||||
import type { DetailEnsemble } from "./types.d.ts";
|
import type { DetailEnsemble } from "./types.d.ts";
|
||||||
|
|
||||||
import { APIClient } from "../../scripts-effect/lib/api.ts";
|
import { APIClient } from "../../scripts-effect/lib/api.ts";
|
||||||
|
import { setLoadingState } from "../../scripts-effect/lib/elements.ts";
|
||||||
import { CartProduct } from "../../scripts-effect/schemas/api.ts";
|
import { CartProduct } from "../../scripts-effect/schemas/api.ts";
|
||||||
import { WooCommerceCart } from "../../scripts-effect/schemas/cart.ts";
|
import { WooCommerceCart } from "../../scripts-effect/schemas/cart.ts";
|
||||||
import { Product, ProductVariation, ProductVariationAttribute } from "../../scripts-effect/schemas/product.ts";
|
import { Product, ProductVariation, ProductVariationAttribute } from "../../scripts-effect/schemas/product.ts";
|
||||||
|
|
@ -98,11 +99,6 @@ class ProductPageDOM extends Context.Service<ProductPageDOM>()(
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const setLoadingState = Effect.fn("setLoadingState")(function*(element: HTMLElement, isLoading: boolean) {
|
|
||||||
element.toggleAttribute(ATTRIBUT_DESACTIVE, isLoading);
|
|
||||||
element.toggleAttribute(ATTRIBUT_CHARGEMENT, isLoading);
|
|
||||||
});
|
|
||||||
|
|
||||||
const detailButtonClickHandler = Effect.fn("detailButtonClickHandler")(
|
const detailButtonClickHandler = Effect.fn("detailButtonClickHandler")(
|
||||||
function*(evt: Event) {
|
function*(evt: Event) {
|
||||||
// Empêche la pollution de l'historique de navigation
|
// Empêche la pollution de l'historique de navigation
|
||||||
|
|
@ -232,7 +228,7 @@ class ProductPageDOM extends Context.Service<ProductPageDOM>()(
|
||||||
// Désactive les interactions le temps de la requête.
|
// Désactive les interactions le temps de la requête.
|
||||||
yield* setLoadingState(AddToCartButton, true);
|
yield* setLoadingState(AddToCartButton, true);
|
||||||
yield* SubscriptionRef.set(AddToCartButtonText, "Adding Product...");
|
yield* SubscriptionRef.set(AddToCartButtonText, "Adding Product...");
|
||||||
// lanceAnimationCycleLoading(AddToCartButton, 500);
|
// LanceAnimationCycleLoading(AddToCartButton, 500);
|
||||||
|
|
||||||
// Exécute la Requête auprès du backend.
|
// Exécute la Requête auprès du backend.
|
||||||
const newCart = yield* API.AddProductToCart(PageStates.nonce, requestBody);
|
const newCart = yield* API.AddProductToCart(PageStates.nonce, requestBody);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ class ProductPageMessages extends Context.Service<ProductPageMessages>()("haikua
|
||||||
const { AddToCartButton } = yield* ProductPageElements;
|
const { AddToCartButton } = yield* ProductPageElements;
|
||||||
|
|
||||||
const AddToCartButtonText = yield* SubscriptionRef.make("Add to cart");
|
const AddToCartButtonText = yield* SubscriptionRef.make("Add to cart");
|
||||||
// const AddToCartErrorText = yield* SubscriptionRef.make<Option.Option<string>>(Option.none());
|
// Const AddToCartErrorText = yield* SubscriptionRef.make<Option.Option<string>>(Option.none());
|
||||||
|
|
||||||
const initAddToCartButtonUpdates = Effect.fn("initAddToCartButtonUpdates")(function*() {
|
const initAddToCartButtonUpdates = Effect.fn("initAddToCartButtonUpdates")(function*() {
|
||||||
return yield* pipe(
|
return yield* pipe(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue