From 006ef44ffddc0b88f1ddb53b1aa2c488af691565 Mon Sep 17 00:00:00 2001 From: David Arranz Date: Fri, 9 Aug 2024 20:12:47 +0200 Subject: [PATCH] =?UTF-8?q?Revisi=C3=B3n=20de=20ajustes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/app/settings/edit.tsx | 381 ++++++++++-------- client/src/app/settings/hooks/useSettings.tsx | 45 ++- client/src/app/settings/layout.tsx | 19 +- client/src/locales/en.json | 60 +-- client/src/locales/es.json | 37 +- .../application/UpdateProfile.useCase.ts | 14 +- .../infrastructure/Profile.repository.ts | 6 +- .../IUpdateProfile_Request.dto.ts | 10 +- 8 files changed, 313 insertions(+), 259 deletions(-) diff --git a/client/src/app/settings/edit.tsx b/client/src/app/settings/edit.tsx index e3da7af..29df1bc 100644 --- a/client/src/app/settings/edit.tsx +++ b/client/src/app/settings/edit.tsx @@ -1,4 +1,4 @@ -import { FormTextAreaField } from "@/components"; +import { ErrorOverlay, FormTextAreaField, LoadingOverlay } from "@/components"; import { Alert, AlertDescription, @@ -15,39 +15,39 @@ import { import { t } from "i18next"; import { AlertCircleIcon } from "lucide-react"; -import { useState } from "react"; +import { useMemo } from "react"; import { SubmitHandler, useForm } from "react-hook-form"; import { Trans } from "react-i18next"; +import { IUpdateProfile_Request_DTO } from "@shared/contexts"; import { Link } from "react-router-dom"; +import { toast } from "react-toastify"; import { useSettings } from "./hooks"; -type SettingsDataForm = { - contact_information: string; - default_payment_method: string; - default_notes: string; - default_legal_terms: string; - default_quote_validity: string; -}; +type SettingsDataForm = IUpdateProfile_Request_DTO; export const SettingsEditor = () => { - const [loading, setLoading] = useState(false); + const { useOne, useUpdate } = useSettings(); - const { useQuery, useMutation } = useSettings(); + const { data, status, error: queryError } = useOne(); - const { data } = useQuery; - const { mutate } = useMutation; - - const form = useForm({ - mode: "onBlur", - values: data, - defaultValues: { + const defaultValues = useMemo( + () => ({ contact_information: "", default_payment_method: "", default_notes: "", default_legal_terms: "", default_quote_validity: "", - }, + }), + [] + ); + + const { mutate } = useUpdate(); + + const form = useForm({ + mode: "onBlur", + values: data?.dealer, + defaultValues, /*resolver: joiResolver( Joi.object({ email: Joi.string() @@ -61,175 +61,198 @@ export const SettingsEditor = () => { ),*/ }); + const { formState } = form; + const { isSubmitting } = formState; + const onSubmit: SubmitHandler = async (data) => { - try { - setLoading(true); - console.log(data); - mutate(data); - } finally { - setLoading(false); - } + console.log(data); + mutate(data, { + onError: (error) => { + console.debug(error); + toast.error(error.message); + //alert(error.message); + }, + //onSettled: () => {}, + onSuccess: () => { + toast("Ajustes guardados"); + //clear(); + }, + }); }; + if (isSubmitting) { + return ; + } + + if (status === "error") { + return ; + } + + if (status !== "success") { + return ; + } + return ( -
- -
- {form.formState.errors.root?.message && ( - - - - - - {form.formState.errors.root?.message} - - )} + <> +
+

+ +

+
- -
- - - - - - - - - - - - - - - - + + +
+ {form.formState.errors.root?.message && ( + + + + + + {form.formState.errors.root?.message} + + )} - - - - - - - - - - - - - - - - + +
+ + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-
- - + + + ); }; diff --git a/client/src/app/settings/hooks/useSettings.tsx b/client/src/app/settings/hooks/useSettings.tsx index e4e0977..ac7ed10 100644 --- a/client/src/app/settings/hooks/useSettings.tsx +++ b/client/src/app/settings/hooks/useSettings.tsx @@ -1,7 +1,12 @@ import { useOne, useSave } from "@/lib/hooks/useDataSource"; +import { TDataSourceError } from "@/lib/hooks/useDataSource/types"; import { useDataSource } from "@/lib/hooks/useDataSource/useDataSource"; import { useQueryKey } from "@/lib/hooks/useQueryKey"; -import { IGetProfileResponse_DTO } from "@shared/contexts"; +import { + IGetProfileResponse_DTO, + IUpdateProfile_Request_DTO, + IUpdateProfileResponse_DTO, +} from "@shared/contexts"; export type UseSettingsGetParamsType = { enabled?: boolean; @@ -13,23 +18,25 @@ export const useSettings = (params?: UseSettingsGetParamsType) => { const keys = useQueryKey(); return { - useQuery: useOne({ - queryKey: keys().data().resource("settings").action("one").id("").params().get(), - queryFn: () => - dataSource.getOne({ - resource: "profile", - id: "", - }), - ...params, - }), - useMutation: useSave({ - mutationKey: keys().data().resource("settings").action("one").id("").params().get(), - mutationFn: (data) => - dataSource.updateOne({ - resource: "profile", - data, - id: "", - }), - }), + useOne: () => + useOne({ + queryKey: keys().data().resource("settings").action("one").id("me").params().get(), + queryFn: () => + dataSource.getOne({ + resource: "profile", + id: "", + }), + ...params, + }), + useUpdate: () => + useSave({ + mutationKey: keys().data().resource("settings").action("one").id("me").params().get(), + mutationFn: (data) => + dataSource.updateOne({ + resource: "profile", + data, + id: "", + }), + }), }; }; diff --git a/client/src/app/settings/layout.tsx b/client/src/app/settings/layout.tsx index b5a968c..7fb0af2 100644 --- a/client/src/app/settings/layout.tsx +++ b/client/src/app/settings/layout.tsx @@ -1,19 +1,14 @@ import { Layout, LayoutContent, LayoutHeader } from "@/components"; import { PropsWithChildren } from "react"; -import { Trans } from "react-i18next"; +import { SettingsProvider } from "./SettingsContext"; export const SettingsLayout = ({ children }: PropsWithChildren) => { return ( - - - -
-

- -

-
- {children} -
-
+ + + + {children} + + ); }; diff --git a/client/src/locales/en.json b/client/src/locales/en.json index ef370bc..7a1fce7 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -6,7 +6,7 @@ "yes": "Yes", "save": "Save", "accept": "OK", - "hide": "Ocultar", + "hide": "Hide", "back": "Back", "upload": "Upload", "continue": "Continue", @@ -25,9 +25,9 @@ "filter_placeholder": "Escribe aquí para filtrar...", "reset_filter": "Quitar el filtro", "error": "Error", - "actions": "Acciones", - "open_menu": "Abrir el menú", - "duplicate_rows": "Duplicar", + "actions": "Actions", + "open_menu": "Open menu", + "duplicate_rows": "Duplicate", "duplicate_rows_tooltip": "Duplica las fila(s) seleccionadas(s)", "pick_date": "Elige una fecha", "required_field": "Este campo es obligatorio", @@ -35,19 +35,19 @@ "edit": "Editar" }, "main_menu": { - "home": "Inicio", - "settings": "Ajustes", - "dealers": "Distribuidores", - "catalog": "Catálogo", - "quotes": "Cotizaciones", - "search_placeholder": "Buscar productos, cotizaciones, etc...", + "home": "Home", + "settings": "Settings", + "dealers": "Dealers", + "catalog": "Catalog", + "quotes": "Quotes", + "search_placeholder": "Type here for search quotes and articles", "user": { - "user_menu": "Menú del usuario", - "my_account": "Mi cuenta", - "profile": "Perfil", - "settings": "Ajustes", - "support": "Soporte", - "logout": "Salir" + "user_menu": "User menu", + "my_account": "My account", + "profile": "Profile", + "settings": "Settings", + "support": "Support", + "logout": "Logout" }, "logout": {} }, @@ -212,14 +212,31 @@ } }, "settings": { - "title": "Ajustes", - "quotes": { - "title": "Cotizaciones", + "edit": { + "title": "Settings", + "subtitle": "", + "tabs": { + "profile": "Profile settings", + "quotes": "Quote settings", + "legal": "Legal settings" + } + }, + "form_fields": { + "image": { + "label": "Información de contacto", + "placeholder": "placeholder", + "desc": "Información de contacto" + }, "contact_information": { "label": "Información de contacto", "placeholder": "placeholder", "desc": "Información de contacto" }, + "default_legal_terms": { + "label": "Cláusulas legales", + "placeholder": "", + "desc": "desc" + }, "default_payment_method": { "label": "Forma de pago", "placeholder": "placeholder", @@ -230,11 +247,6 @@ "placeholder": "", "desc": "desc" }, - "default_legal_terms": { - "label": "Cláusulas legales", - "placeholder": "", - "desc": "desc" - }, "default_quote_validity": { "label": "Validez por defecto", "placeholder": "", diff --git a/client/src/locales/es.json b/client/src/locales/es.json index 54677d0..d5f4095 100644 --- a/client/src/locales/es.json +++ b/client/src/locales/es.json @@ -224,13 +224,33 @@ }, "settings": { "title": "Ajustes", + "profile": { + "title": "Ajustes de perfil", + "items": { + "image": { + "label": "Información de contacto", + "placeholder": "placeholder", + "desc": "Información de contacto" + }, + "contact_information": { + "label": "Información de contacto", + "placeholder": "placeholder", + "desc": "Información de contacto" + } + } + }, + "legal": { + "title": "Ajustes legales", + "items": { + "default_legal_terms": { + "label": "Cláusulas legales", + "placeholder": "", + "desc": "desc" + } + } + }, "quotes": { - "title": "Cotizaciones", - "contact_information": { - "label": "Información de contacto", - "placeholder": "placeholder", - "desc": "Información de contacto" - }, + "title": "Ajustes para cotizaciones", "default_payment_method": { "label": "Forma de pago", "placeholder": "placeholder", @@ -241,11 +261,6 @@ "placeholder": "", "desc": "desc" }, - "default_legal_terms": { - "label": "Cláusulas legales", - "placeholder": "", - "desc": "desc" - }, "default_quote_validity": { "label": "Validez por defecto", "placeholder": "", diff --git a/server/src/contexts/profile/application/UpdateProfile.useCase.ts b/server/src/contexts/profile/application/UpdateProfile.useCase.ts index 35e5379..08e63a9 100644 --- a/server/src/contexts/profile/application/UpdateProfile.useCase.ts +++ b/server/src/contexts/profile/application/UpdateProfile.useCase.ts @@ -7,7 +7,7 @@ import { import { IRepositoryManager } from "@/contexts/common/domain"; import { IInfrastructureError } from "@/contexts/common/infrastructure"; import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize"; -import { IUpdateProfile_Request_DTO, Note, Result, UniqueID } from "@shared/contexts"; +import { IUpdateProfile_Request_DTO, Result, TextValueObject, UniqueID } from "@shared/contexts"; import { IProfileRepository, Profile } from "../domain"; export interface IUpdateProfileUseCaseRequest extends IUseCaseRequest { @@ -33,6 +33,8 @@ export class UpdateProfileUseCase async execute(request: IUpdateProfileUseCaseRequest): Promise { const { userId, profileDTO } = request; + console.log(request); + // Comprobar que existe el profile const exitsOrError = await this._getProfileDealer(userId); if (exitsOrError.isFailure) { @@ -47,11 +49,11 @@ export class UpdateProfileUseCase const profile = exitsOrError.object; // Actualizar el perfil con datos actualizados - profile.contactInformation = Note.create(profileDTO.contact_information).object; - profile.defaultPaymentMethod = Note.create(profileDTO.default_payment_method).object; - profile.defaultLegalTerms = Note.create(profileDTO.default_legal_terms).object; - profile.defaultNotes = Note.create(profileDTO.default_notes).object; - profile.defaultQuoteValidity = Note.create(profileDTO.default_quote_validity).object; + profile.contactInformation = TextValueObject.create(profileDTO.contact_information).object; + profile.defaultPaymentMethod = TextValueObject.create(profileDTO.default_payment_method).object; + profile.defaultLegalTerms = TextValueObject.create(profileDTO.default_legal_terms).object; + profile.defaultNotes = TextValueObject.create(profileDTO.default_notes).object; + profile.defaultQuoteValidity = TextValueObject.create(profileDTO.default_quote_validity).object; // Guardar los cambios return this._saveProfile(profile); diff --git a/server/src/contexts/profile/infrastructure/Profile.repository.ts b/server/src/contexts/profile/infrastructure/Profile.repository.ts index 3d83409..c79dd01 100644 --- a/server/src/contexts/profile/infrastructure/Profile.repository.ts +++ b/server/src/contexts/profile/infrastructure/Profile.repository.ts @@ -19,11 +19,11 @@ export class ProfileRepository extends SequelizeRepository implements I } public async exists(id: UniqueID): Promise { - return this._exists("Profile_Model", "id", id.toPrimitive()); + return this._exists("Dealer_Model", "id", id.toPrimitive()); } public async getById(id: UniqueID): Promise { - const rawProfile: any = await this._getById("Profile_Model", id); + const rawProfile: any = await this._getById("Dealer_Model", id); if (!rawProfile === true) { return null; @@ -37,7 +37,7 @@ export class ProfileRepository extends SequelizeRepository implements I // borrando y luego creando // await this.removeById(user.id, true); - await this._save("Profile_Model", profile.id, userData, {}); + await this._save("Dealer_Model", profile.id, userData, {}); } public async getByUserId(userId: UniqueID): Promise { diff --git a/shared/lib/contexts/profile/application/dto/UpdateProfile.dto/IUpdateProfile_Request.dto.ts b/shared/lib/contexts/profile/application/dto/UpdateProfile.dto/IUpdateProfile_Request.dto.ts index a69ce8b..4d96d97 100644 --- a/shared/lib/contexts/profile/application/dto/UpdateProfile.dto/IUpdateProfile_Request.dto.ts +++ b/shared/lib/contexts/profile/application/dto/UpdateProfile.dto/IUpdateProfile_Request.dto.ts @@ -11,11 +11,11 @@ export interface IUpdateProfile_Request_DTO { export function ensureUpdateProfile_Request_DTOIsValid(userDTO: IUpdateProfile_Request_DTO) { const schema = Joi.object({ - contact_information: Joi.string(), - default_payment_method: Joi.string(), - default_notes: Joi.string(), - default_legal_terms: Joi.string(), - default_quote_validity: Joi.string(), + contact_information: Joi.string().optional().allow(null).allow("").default(""), + default_payment_method: Joi.string().optional().allow(null).allow("").default(""), + default_notes: Joi.string().optional().allow(null).allow("").default(""), + default_legal_terms: Joi.string().optional().allow(null).allow("").default(""), + default_quote_validity: Joi.string().optional().allow(null).allow("").default(""), }).unknown(true); const result = RuleValidator.validate(schema, userDTO);