From ec9923dac8f4da5877c7b9de550fc0079bab25f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20Luna=20Hern=C3=A1ndez?= <42101656@uaz.edu.mx> Date: Tue, 5 Nov 2024 15:44:27 -0600 Subject: [PATCH 1/3] Reorganizacion de archivos --- web/public/index.html | 5 +- web/public/logotipo.png | Bin 0 -> 12368 bytes web/src/App.tsx | 7 +- .../admin_panel_navbar/admin_navbar.tsx | 173 ------------ .../admin_panel_place_list.tsx | 74 ----- .../admin_panel_poi_list.tsx | 157 ----------- .../admin_panel_poi_register.tsx | 205 -------------- .../admin_panel_poi_screen.tsx | 89 ------ .../admin_panel_poi_viewer.tsx | 176 ------------ .../admin_town_info/admin_town_info.tsx | 119 -------- .../confirmation_dialog.tsx | 40 --- .../image_dropzone/image_dropzone.tsx | 57 ---- .../loading_screen/loading_screen.tsx | 9 - .../multiple_images_dropzone.tsx | 51 ---- .../sa_panel_admin_list.tsx | 149 ---------- .../sa_panel_admin_register.tsx | 158 ----------- .../sa_panel_admin_screen.tsx | 50 ---- .../sa_panel_category_list.tsx | 102 ------- .../sa_panel_category_register.tsx | 60 ---- .../sa_panel_town_register.tsx | 163 ----------- .../sa_panel_town_screen.tsx | 50 ---- .../sidebar_header/sidebar_header.tsx | 18 -- web/src/constants/images_nuber.ts | 1 - web/src/constants/languages.ts | 4 - web/src/constants/roles.ts | 7 - web/src/constants/selected_panel.ts | 11 - web/src/context/auth_context.tsx | 68 ----- web/src/{ => core}/constants/api_routes.ts | 41 ++- web/src/{ => core}/constants/api_url.ts | 3 + web/src/core/constants/images_nuber.ts | 4 + web/src/core/constants/languages.ts | 7 + web/src/core/constants/roles.ts | 17 ++ web/src/core/constants/selected_panel.ts | 17 ++ web/src/core/context/auth_context.tsx | 92 ++++++ .../{ => core}/context/message_context.tsx | 25 +- web/src/core/errors/CustomError.ts | 26 ++ web/src/core/errors/UnautherizedError.ts | 56 ++++ web/src/core/router/login_route.tsx | 15 + web/src/core/router/protected_route.tsx | 26 ++ web/src/core/router/router.tsx | 30 ++ web/src/core/utils/Messages.ts | 36 +++ web/src/data/datasource/admin_datasource.ts | 55 ++++ .../api}/admin_datasource.ts | 49 +++- .../datasource/api/category_datasource.ts | 62 +++++ .../api}/entities/admin_form_values.ts | 13 +- .../data/datasource/api/entities/category.ts | 16 ++ web/src/data/datasource/api/entities/image.ts | 7 + .../api/entities/login_form_values.ts | 7 + .../datasource/api}/entities/place.ts | 27 +- .../datasource/api}/entities/poi.ts | 8 +- .../api}/entities/reset_password_values.ts | 3 + web/src/data/datasource/api/entities/state.ts | 8 + web/src/data/datasource/api/entities/town.ts | 12 + web/src/data/datasource/api/entities/user.ts | 223 +++++++++++++++ .../data/datasource/api/login_datasource.ts | 41 +++ .../data/datasource/api/place_datasource.ts | 128 +++++++++ web/src/data/datasource/api/poi_datasource.ts | 106 +++++++ .../data/datasource/api/town_datasource.ts | 115 ++++++++ .../data/datasource/category_datasource.ts | 26 ++ web/src/data/datasource/login_datasource.ts | 14 + web/src/data/datasource/place_datasource.ts | 34 +++ web/src/data/datasource/poi_datasource.ts | 35 +++ web/src/data/datasource/town_datasource.ts | 41 +++ .../datasources/prod/category_datasource.ts | 45 --- .../data/datasources/prod/login_datasource.ts | 30 -- .../data/datasources/prod/place_datasource.ts | 94 ------- .../data/datasources/prod/poi_datasource.ts | 70 ----- .../data/datasources/prod/town_datasource.ts | 86 ------ web/src/data/models/prod/AdminModel.ts | 8 - web/src/data/models/prod/CategoryModel.ts | 10 - web/src/data/models/prod/LoggedInUserModel.ts | 6 - web/src/data/models/prod/POIModel.ts | 24 -- web/src/data/models/prod/PlaceModel.ts | 55 ---- web/src/data/models/prod/StateModel.ts | 5 - web/src/data/models/prod/TownModel.ts | 16 -- .../repositories/prod/admin_repository.ts | 39 --- .../repositories/prod/category_repository.ts | 21 -- .../repositories/prod/login_repository.ts | 13 - .../repositories/prod/place_repository.ts | 24 -- .../data/repositories/prod/poi_repository.ts | 25 -- .../data/repositories/prod/town_repository.ts | 25 -- web/src/data/repository/admin_repository.ts | 74 +++++ .../data/repository/category_repository.ts | 39 +++ web/src/data/repository/login_repository.ts | 20 ++ web/src/data/repository/place_repository.ts | 46 +++ web/src/data/repository/poi_repository.ts | 47 ++++ web/src/data/repository/town_repository.ts | 56 ++++ web/src/domain/model/AdminModel.ts | 17 ++ web/src/domain/model/CategoryModel.ts | 21 ++ web/src/domain/model/LoggedInUserModel.ts | 24 ++ web/src/domain/model/POIModel.ts | 38 +++ web/src/domain/model/PlaceModel.ts | 77 +++++ web/src/domain/model/StateModel.ts | 11 + web/src/domain/model/TownModel.ts | 33 +++ web/src/domain/repository/admin_repository.ts | 58 ++++ .../domain/repository/category_repository.ts | 29 ++ web/src/domain/repository/login_repository.ts | 14 + web/src/domain/repository/place_repository.ts | 34 +++ web/src/domain/repository/poi_repository.ts | 35 +++ web/src/domain/repository/town_repository.ts | 42 +++ .../useCase/useAdmin.ts} | 27 +- .../domain/useCase/useAdminChangePassword.ts | 106 +++++++ .../useCase/useAdminHomePage.ts} | 49 ++-- .../useCase/useAdminTownInfo.ts} | 5 + web/src/domain/useCase/useCategory.ts | 145 ++++++++++ .../useCase/useDropzoneMultiplesImages.ts | 102 +++++++ web/src/domain/useCase/useGetStatesList.ts | 51 ++++ web/src/domain/useCase/useLogin.ts | 104 +++++++ .../useCase/usePasswordVisibility.ts} | 8 +- .../useCase/usePlace.ts} | 36 ++- .../useCase/usePointOfInterest.ts} | 172 +++++++----- .../useCase}/useResetPassword.ts | 15 +- .../useCase/useSuperadminHomePage.ts} | 46 +-- .../useTown.tsx => domain/useCase/useTown.ts} | 164 ++++++----- web/src/domain/useCase/useUserData.ts | 32 +++ web/src/domain/useCase/useWindowShow.ts | 22 ++ web/src/errors/CustomError.ts | 15 - web/src/errors/UnautherizedError.ts | 31 --- web/src/hooks/useAdminChangePassword.tsx | 88 ------ web/src/hooks/useCategory.tsx | 129 --------- web/src/hooks/useDropzoneMultiplesImages.tsx | 95 ------- web/src/hooks/useGetStatesList.tsx | 44 --- web/src/hooks/useLogin.tsx | 86 ------ web/src/hooks/useUserData.tsx | 21 -- web/src/hooks/useWindowShow.tsx | 12 - .../datasources/admin_datasource.ts | 15 - .../datasources/category_datasource.ts | 7 - .../datasources/login_datasource.ts | 6 - .../datasources/place_datasource.ts | 8 - .../datasources/poi_datasource.ts | 8 - .../datasources/town_datasource.ts | 10 - web/src/infraestructure/entities/category.ts | 10 - web/src/infraestructure/entities/image.ts | 4 - .../entities/login_form_values.ts | 4 - web/src/infraestructure/entities/state.ts | 5 - web/src/infraestructure/entities/town.ts | 9 - web/src/infraestructure/entities/user.ts | 189 ------------- .../repositories/admin_repository.ts | 15 - .../repositories/category_repository.ts | 7 - .../repositories/login_repository.ts | 6 - .../repositories/place_repository.ts | 8 - .../repositories/poi_repository.ts | 8 - .../repositories/town_repository.ts | 10 - .../pages/home/admin_page/admin_home_page.tsx | 97 ------- .../super_admin_home_page.tsx | 107 ------- .../admin/admin_panel_navbar/admin_navbar.tsx | 199 +++++++++++++ .../images/Admin-595b40b65ba036ed117d36fe.png | Bin .../assets/styles/style.css | 65 +++-- .../admin_panel_place_list.tsx | 90 ++++++ .../assets/css/styles.css | 0 .../admin_panel_place_register.tsx | 36 ++- .../assets/css/styles.css | 0 .../admin_panel_place_screen.tsx | 66 +++-- .../assets/css/styles.css | 0 .../admin_panel_poi_list.tsx | 187 +++++++++++++ .../assets/css/styles.css | 0 .../admin_panel_poi_register.tsx | 263 ++++++++++++++++++ .../assets/css/styles.css | 0 .../admin_panel_poi_screen.tsx | 116 ++++++++ .../assets/css/styles.css | 0 .../admin_panel_poi_viewer.tsx | 191 +++++++++++++ .../assets/css/styles.css | 0 .../admin/admin_town_info/admin_town_info.tsx | 147 ++++++++++ .../admin_town_info/assets/css/styles.css | 0 .../admin/panel/admin_home_page.tsx | 147 ++++++++++ .../admin/panel}/assets/styles/style.css | 0 .../assets/css/styles.css | 0 .../confirmation_dialog.tsx | 58 ++++ .../error_window/assets/css/styles.css | 0 .../components/error_window/error_window.tsx | 13 +- .../components/footer/assets/css/styles.css | 0 .../components/footer/footer.tsx | 9 + .../geocoding/assets/css/styles.css | 0 .../components/geocoding/geocoding_google.tsx | 15 +- .../components/geocoding/geocoding_mapbox.tsx | 7 +- .../image_dropzone/assets/css/styles.css | 0 .../image_dropzone/image_dropzone.tsx | 70 +++++ .../loading_screen/assets/css/styles.css | 0 .../loading_screen/loading_screen.tsx | 12 + .../loading_spinner/assets/css/styles.css | 0 .../loading_spinner/loading_spinner.tsx | 2 + .../components/map/map_google.tsx | 10 +- .../components/map/map_mapbox.tsx | 11 +- .../assets/css/styles.css | 0 .../multiple_images_dropzone.tsx | 50 ++++ .../assets/css/styles.css | 0 .../reset_password_window.tsx | 9 +- .../sidebar_header/assets/css/styles.css | 0 .../sidebar_header/sidebar_header.tsx | 23 ++ .../login}/login_page.tsx | 24 +- .../login}/styles/styles.css | 0 .../superadmin/panel}/assets/styles/style.css | 0 .../panel/super_admin_home_page.tsx | 146 ++++++++++ .../sa_panel_admin_list/assets/css/styles.css | 0 .../sa_panel_admin_list.tsx | 170 +++++++++++ .../assets/css/styles.css | 0 .../sa_panel_admin_register.tsx | 170 +++++++++++ .../assets/css/styles.css | 0 .../sa_panel_admin_screen.tsx | 67 +++++ .../assets/css/styles.css | 0 .../sa_panel_category_list.tsx | 119 ++++++++ .../assets/css/styles.css | 0 .../sa_panel_category_register.tsx | 61 ++++ .../assets/css/styles.css | 0 .../sa_panel_category_screen.tsx | 10 +- .../sa_panel_town_list/assets/css/styles.css | 0 .../sa_panel_town_list/sa_panel_town_list.tsx | 40 ++- .../sa_panel_town_register/css/styles.css | 40 +-- .../sa_panel_town_register.tsx | 194 +++++++++++++ .../sa_panel_town_screen/css/styles.css | 0 .../sa_panel_town_screen.tsx | 67 +++++ web/src/router/login_route.tsx | 10 - web/src/router/protected_route.tsx | 27 -- web/src/router/router.tsx | 28 -- web/src/utils/Messages.ts | 27 -- 215 files changed, 5781 insertions(+), 4092 deletions(-) create mode 100644 web/public/logotipo.png delete mode 100644 web/src/components/admin_panel_navbar/admin_navbar.tsx delete mode 100644 web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx delete mode 100644 web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx delete mode 100644 web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx delete mode 100644 web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx delete mode 100644 web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx delete mode 100644 web/src/components/admin_town_info/admin_town_info.tsx delete mode 100644 web/src/components/confirmation_dialog_box/confirmation_dialog.tsx delete mode 100644 web/src/components/image_dropzone/image_dropzone.tsx delete mode 100644 web/src/components/loading_screen/loading_screen.tsx delete mode 100644 web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx delete mode 100644 web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx delete mode 100644 web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx delete mode 100644 web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx delete mode 100644 web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx delete mode 100644 web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx delete mode 100644 web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx delete mode 100644 web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx delete mode 100644 web/src/components/sidebar_header/sidebar_header.tsx delete mode 100644 web/src/constants/images_nuber.ts delete mode 100644 web/src/constants/languages.ts delete mode 100644 web/src/constants/roles.ts delete mode 100644 web/src/constants/selected_panel.ts delete mode 100644 web/src/context/auth_context.tsx rename web/src/{ => core}/constants/api_routes.ts (53%) rename web/src/{ => core}/constants/api_url.ts (62%) create mode 100644 web/src/core/constants/images_nuber.ts create mode 100644 web/src/core/constants/languages.ts create mode 100644 web/src/core/constants/roles.ts create mode 100644 web/src/core/constants/selected_panel.ts create mode 100644 web/src/core/context/auth_context.tsx rename web/src/{ => core}/context/message_context.tsx (50%) create mode 100644 web/src/core/errors/CustomError.ts create mode 100644 web/src/core/errors/UnautherizedError.ts create mode 100644 web/src/core/router/login_route.tsx create mode 100644 web/src/core/router/protected_route.tsx create mode 100644 web/src/core/router/router.tsx create mode 100644 web/src/core/utils/Messages.ts create mode 100644 web/src/data/datasource/admin_datasource.ts rename web/src/data/{datasources/prod => datasource/api}/admin_datasource.ts (58%) create mode 100644 web/src/data/datasource/api/category_datasource.ts rename web/src/{infraestructure => data/datasource/api}/entities/admin_form_values.ts (61%) create mode 100644 web/src/data/datasource/api/entities/category.ts create mode 100644 web/src/data/datasource/api/entities/image.ts create mode 100644 web/src/data/datasource/api/entities/login_form_values.ts rename web/src/{infraestructure => data/datasource/api}/entities/place.ts (69%) rename web/src/{infraestructure => data/datasource/api}/entities/poi.ts (76%) rename web/src/{infraestructure => data/datasource/api}/entities/reset_password_values.ts (62%) create mode 100644 web/src/data/datasource/api/entities/state.ts create mode 100644 web/src/data/datasource/api/entities/town.ts create mode 100644 web/src/data/datasource/api/entities/user.ts create mode 100644 web/src/data/datasource/api/login_datasource.ts create mode 100644 web/src/data/datasource/api/place_datasource.ts create mode 100644 web/src/data/datasource/api/poi_datasource.ts create mode 100644 web/src/data/datasource/api/town_datasource.ts create mode 100644 web/src/data/datasource/category_datasource.ts create mode 100644 web/src/data/datasource/login_datasource.ts create mode 100644 web/src/data/datasource/place_datasource.ts create mode 100644 web/src/data/datasource/poi_datasource.ts create mode 100644 web/src/data/datasource/town_datasource.ts delete mode 100644 web/src/data/datasources/prod/category_datasource.ts delete mode 100644 web/src/data/datasources/prod/login_datasource.ts delete mode 100644 web/src/data/datasources/prod/place_datasource.ts delete mode 100644 web/src/data/datasources/prod/poi_datasource.ts delete mode 100644 web/src/data/datasources/prod/town_datasource.ts delete mode 100644 web/src/data/models/prod/AdminModel.ts delete mode 100644 web/src/data/models/prod/CategoryModel.ts delete mode 100644 web/src/data/models/prod/LoggedInUserModel.ts delete mode 100644 web/src/data/models/prod/POIModel.ts delete mode 100644 web/src/data/models/prod/PlaceModel.ts delete mode 100644 web/src/data/models/prod/StateModel.ts delete mode 100644 web/src/data/models/prod/TownModel.ts delete mode 100644 web/src/data/repositories/prod/admin_repository.ts delete mode 100644 web/src/data/repositories/prod/category_repository.ts delete mode 100644 web/src/data/repositories/prod/login_repository.ts delete mode 100644 web/src/data/repositories/prod/place_repository.ts delete mode 100644 web/src/data/repositories/prod/poi_repository.ts delete mode 100644 web/src/data/repositories/prod/town_repository.ts create mode 100644 web/src/data/repository/admin_repository.ts create mode 100644 web/src/data/repository/category_repository.ts create mode 100644 web/src/data/repository/login_repository.ts create mode 100644 web/src/data/repository/place_repository.ts create mode 100644 web/src/data/repository/poi_repository.ts create mode 100644 web/src/data/repository/town_repository.ts create mode 100644 web/src/domain/model/AdminModel.ts create mode 100644 web/src/domain/model/CategoryModel.ts create mode 100644 web/src/domain/model/LoggedInUserModel.ts create mode 100644 web/src/domain/model/POIModel.ts create mode 100644 web/src/domain/model/PlaceModel.ts create mode 100644 web/src/domain/model/StateModel.ts create mode 100644 web/src/domain/model/TownModel.ts create mode 100644 web/src/domain/repository/admin_repository.ts create mode 100644 web/src/domain/repository/category_repository.ts create mode 100644 web/src/domain/repository/login_repository.ts create mode 100644 web/src/domain/repository/place_repository.ts create mode 100644 web/src/domain/repository/poi_repository.ts create mode 100644 web/src/domain/repository/town_repository.ts rename web/src/{hooks/useAdmin.tsx => domain/useCase/useAdmin.ts} (81%) create mode 100644 web/src/domain/useCase/useAdminChangePassword.ts rename web/src/{hooks/useAdminHomePage.tsx => domain/useCase/useAdminHomePage.ts} (57%) rename web/src/{hooks/useAdminTownInfo.tsx => domain/useCase/useAdminTownInfo.ts} (73%) create mode 100644 web/src/domain/useCase/useCategory.ts create mode 100644 web/src/domain/useCase/useDropzoneMultiplesImages.ts create mode 100644 web/src/domain/useCase/useGetStatesList.ts create mode 100644 web/src/domain/useCase/useLogin.ts rename web/src/{hooks/usePasswordVisibility.tsx => domain/useCase/usePasswordVisibility.ts} (61%) rename web/src/{hooks/usePlace.tsx => domain/useCase/usePlace.ts} (86%) rename web/src/{hooks/usePointOfInterest.tsx => domain/useCase/usePointOfInterest.ts} (50%) rename web/src/{hooks => domain/useCase}/useResetPassword.ts (90%) rename web/src/{hooks/useSuperadminHomePage.tsx => domain/useCase/useSuperadminHomePage.ts} (57%) rename web/src/{hooks/useTown.tsx => domain/useCase/useTown.ts} (51%) create mode 100644 web/src/domain/useCase/useUserData.ts create mode 100644 web/src/domain/useCase/useWindowShow.ts delete mode 100644 web/src/errors/CustomError.ts delete mode 100644 web/src/errors/UnautherizedError.ts delete mode 100644 web/src/hooks/useAdminChangePassword.tsx delete mode 100644 web/src/hooks/useCategory.tsx delete mode 100644 web/src/hooks/useDropzoneMultiplesImages.tsx delete mode 100644 web/src/hooks/useGetStatesList.tsx delete mode 100644 web/src/hooks/useLogin.tsx delete mode 100644 web/src/hooks/useUserData.tsx delete mode 100644 web/src/hooks/useWindowShow.tsx delete mode 100644 web/src/infraestructure/datasources/admin_datasource.ts delete mode 100644 web/src/infraestructure/datasources/category_datasource.ts delete mode 100644 web/src/infraestructure/datasources/login_datasource.ts delete mode 100644 web/src/infraestructure/datasources/place_datasource.ts delete mode 100644 web/src/infraestructure/datasources/poi_datasource.ts delete mode 100644 web/src/infraestructure/datasources/town_datasource.ts delete mode 100644 web/src/infraestructure/entities/category.ts delete mode 100644 web/src/infraestructure/entities/image.ts delete mode 100644 web/src/infraestructure/entities/login_form_values.ts delete mode 100644 web/src/infraestructure/entities/state.ts delete mode 100644 web/src/infraestructure/entities/town.ts delete mode 100644 web/src/infraestructure/entities/user.ts delete mode 100644 web/src/infraestructure/repositories/admin_repository.ts delete mode 100644 web/src/infraestructure/repositories/category_repository.ts delete mode 100644 web/src/infraestructure/repositories/login_repository.ts delete mode 100644 web/src/infraestructure/repositories/place_repository.ts delete mode 100644 web/src/infraestructure/repositories/poi_repository.ts delete mode 100644 web/src/infraestructure/repositories/town_repository.ts delete mode 100644 web/src/pages/home/admin_page/admin_home_page.tsx delete mode 100644 web/src/pages/home/super_admin_page/super_admin_home_page.tsx create mode 100644 web/src/presentation/admin/admin_panel_navbar/admin_navbar.tsx rename web/src/{components => presentation/admin}/admin_panel_navbar/assets/images/Admin-595b40b65ba036ed117d36fe.png (100%) rename web/src/{components => presentation/admin}/admin_panel_navbar/assets/styles/style.css (70%) create mode 100644 web/src/presentation/admin/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx rename web/src/{components => presentation/admin}/admin_panel_places/admin_panel_place_list/assets/css/styles.css (100%) rename web/src/{components => presentation/admin}/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx (91%) rename web/src/{components => presentation/admin}/admin_panel_places/admin_panel_place_register/assets/css/styles.css (100%) rename web/src/{components => presentation/admin}/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx (53%) rename web/src/{components => presentation/admin}/admin_panel_places/admin_panel_place_screen/assets/css/styles.css (100%) create mode 100644 web/src/presentation/admin/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx rename web/src/{components => presentation/admin}/admin_panel_poi/admin_panel_poi_list/assets/css/styles.css (100%) create mode 100644 web/src/presentation/admin/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx rename web/src/{components => presentation/admin}/admin_panel_poi/admin_panel_poi_register/assets/css/styles.css (100%) create mode 100644 web/src/presentation/admin/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx rename web/src/{components => presentation/admin}/admin_panel_poi/admin_panel_poi_screen/assets/css/styles.css (100%) create mode 100644 web/src/presentation/admin/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx rename web/src/{components => presentation/admin}/admin_panel_poi/admin_panel_poi_viewer/assets/css/styles.css (100%) create mode 100644 web/src/presentation/admin/admin_town_info/admin_town_info.tsx rename web/src/{components => presentation/admin}/admin_town_info/assets/css/styles.css (100%) create mode 100644 web/src/presentation/admin/panel/admin_home_page.tsx rename web/src/{pages/home/admin_page => presentation/admin/panel}/assets/styles/style.css (100%) rename web/src/{ => presentation}/components/confirmation_dialog_box/assets/css/styles.css (100%) create mode 100644 web/src/presentation/components/confirmation_dialog_box/confirmation_dialog.tsx rename web/src/{ => presentation}/components/error_window/assets/css/styles.css (100%) rename web/src/{ => presentation}/components/error_window/error_window.tsx (59%) rename web/src/{ => presentation}/components/footer/assets/css/styles.css (100%) rename web/src/{ => presentation}/components/footer/footer.tsx (89%) rename web/src/{ => presentation}/components/geocoding/assets/css/styles.css (100%) rename web/src/{ => presentation}/components/geocoding/geocoding_google.tsx (75%) rename web/src/{ => presentation}/components/geocoding/geocoding_mapbox.tsx (84%) rename web/src/{ => presentation}/components/image_dropzone/assets/css/styles.css (100%) create mode 100644 web/src/presentation/components/image_dropzone/image_dropzone.tsx rename web/src/{ => presentation}/components/loading_screen/assets/css/styles.css (100%) create mode 100644 web/src/presentation/components/loading_screen/loading_screen.tsx rename web/src/{ => presentation}/components/loading_spinner/assets/css/styles.css (100%) rename web/src/{ => presentation}/components/loading_spinner/loading_spinner.tsx (57%) rename web/src/{ => presentation}/components/map/map_google.tsx (79%) rename web/src/{ => presentation}/components/map/map_mapbox.tsx (81%) rename web/src/{ => presentation}/components/multiple_images_dropzone/assets/css/styles.css (100%) create mode 100644 web/src/presentation/components/multiple_images_dropzone/multiple_images_dropzone.tsx rename web/src/{ => presentation}/components/reset_password_window/assets/css/styles.css (100%) rename web/src/{ => presentation}/components/reset_password_window/reset_password_window.tsx (91%) rename web/src/{ => presentation}/components/sidebar_header/assets/css/styles.css (100%) create mode 100644 web/src/presentation/components/sidebar_header/sidebar_header.tsx rename web/src/{pages/login_page => presentation/login}/login_page.tsx (80%) rename web/src/{pages/login_page => presentation/login}/styles/styles.css (100%) rename web/src/{pages/home/super_admin_page => presentation/superadmin/panel}/assets/styles/style.css (100%) create mode 100644 web/src/presentation/superadmin/panel/super_admin_home_page.tsx rename web/src/{components => presentation/superadmin}/sa_panel_admin/sa_panel_admin_list/assets/css/styles.css (100%) create mode 100644 web/src/presentation/superadmin/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx rename web/src/{components => presentation/superadmin}/sa_panel_admin/sa_panel_admin_register/assets/css/styles.css (100%) create mode 100644 web/src/presentation/superadmin/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx rename web/src/{components => presentation/superadmin}/sa_panel_admin/sa_panel_admin_screen/assets/css/styles.css (100%) create mode 100644 web/src/presentation/superadmin/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx rename web/src/{components => presentation/superadmin}/sa_panel_category/sa_panel_category_list/assets/css/styles.css (100%) create mode 100644 web/src/presentation/superadmin/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx rename web/src/{components => presentation/superadmin}/sa_panel_category/sa_panel_category_register/assets/css/styles.css (100%) create mode 100644 web/src/presentation/superadmin/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx rename web/src/{components => presentation/superadmin}/sa_panel_category/sa_panel_category_screen/assets/css/styles.css (100%) rename web/src/{components => presentation/superadmin}/sa_panel_category/sa_panel_category_screen/sa_panel_category_screen.tsx (76%) rename web/src/{components => presentation/superadmin}/sa_panel_town/sa_panel_town_list/assets/css/styles.css (100%) rename web/src/{components => presentation/superadmin}/sa_panel_town/sa_panel_town_list/sa_panel_town_list.tsx (77%) rename web/src/{components => presentation/superadmin}/sa_panel_town/sa_panel_town_register/css/styles.css (83%) create mode 100644 web/src/presentation/superadmin/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx rename web/src/{components => presentation/superadmin}/sa_panel_town/sa_panel_town_screen/css/styles.css (100%) create mode 100644 web/src/presentation/superadmin/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx delete mode 100644 web/src/router/login_route.tsx delete mode 100644 web/src/router/protected_route.tsx delete mode 100644 web/src/router/router.tsx delete mode 100644 web/src/utils/Messages.ts diff --git a/web/public/index.html b/web/public/index.html index aa069f27..babfdb0e 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -2,14 +2,13 @@
- + - -;dKkZa|qS6*MU z`PTKVR-TWh+CI<9zJK#{caVZYu7<7biqx=!hGrl`IX0xc;TD!SvPf0yhO@M^g?02q zg_DH^8{}Cp>R4ReA9?@6?4Z(R)~&z7u7Pwga!qS!v=iNNMbR($_^$qnuD^$Y_Ws{o? !Ur+0_L zK_Q8pzS^C#b@R@pU-O=p?!I=*=}xZrwauUUqh?LJ)_wP%Ld@1!zs%6DcN5ksT)ThB z(CiTttG7bTtGAz7W;1ne)L*7kSomgAYvs!8y7Mn+2q_n@xw$rEUe1K6roBtVUsxNR z+xBhk;<(LxeH#V&H6m=<<$f>PZx9_Bb9tqT#kW+RJ5L|ZQ v2$g88{w%q*yYi?aK}E4Vp__eyvDx xe zx|6bN-8$volzQ&tH#oRObmR_Py&?W0*j37IL*nT+6NM0;uPb#}S$413;}>|#WNKjL zF^gq0BkH-2-SGIU7Mjugz+59j=J3@U(=SZTQ+=?!i*wF=VbO!@CmU~YlwgSoyq7ec zQBXPPukHrNJ5wbJK1}pIxIVe_gnz&Wi>AKIQ?^^BOp^J{RI3#^W4Tq{)Y!5n6O(?I z`KN*o6o*xnY3$vy&bl|`47< DvoCquypNnv=>N05Y`M_vvc@wqB05Y3mfu{(UM+33@ZDn) zvO$%vLsa&YT4B{L#k8a8>un})XsvRoVBr$$o^fx{8E~j^{=C9nSGUCZp8ngO`VZ$U z_WQ4NZ*gCcu(9D~U&9mKQ VivuM`X!rhtzUZF+c1KG^|aFwvu~~3J7#@!jh~g+ce?(`>H4=)zmBKx-oL-- z>9>8B%>}wYZl3>VReyY&c;WJ+HX0FP4#zV+`fC?HHp%I$Rb-qyS0{7M2^Gz6TTaJs zO7e1!pXI1~S4@LB_TG*EFSjJQCJX3ZkN +3p<=GL@SbB%Ebf=eO=m zF2`rdb(Q6Ii`N<`&SGufx>0@>OQ|tevmCJq25aX7=x9j@LhifCRD1&NtbBF1AF?SZ_cskGM zFL)Sa&Rc1`Q+uo1hB;+9^@R_azwdVg8|uoql)JBXBj38J+MKpM`rEhu^tbuk{VP&f zIPLtb^1tWpbILqA!UOv`m~ZS!m}#|Ur^N3hU*{S61y6&PpWU3(zDNK6FY{ZSv!XV$ zah&`5A*1le=lLn;yr(Z}oZ^@hwP8m=1oJX$CdK2K43|BGGN HtQ)XS|=VNoW<=x#~aQg51p!__~{|6RiySkR%S?X;&Z|z#~UZ?l3U*FwR zva&k8 Z_Bul$(5g;L`M4i&wqZjFK=-|Wp$;=?%lh~++5aN zTkFpe?&|J7#bQDBy$)YaG1=vcw%=O&E_Wop;l8d{x-RV^f84GomfvT;pC_rQd1{7D z`MYJ;CrF+?@Z-mugHxU`-^;#!ZI8V!LS{e~SM+KXvN$yJg{0%Dh+A)IF|j+?Z{e zxKPooo_FS14zV{Yj#PCUY3|ribzmWj?c?s(&YU+gugcrcdw2cHl%ln(Z~y=OF!Axa zA~TlxwbQT9kKDDzs^agjIWNn?dV8Ncm;HZt*7+;%S>s>TFWzifps%LpGh2f@O!dg| zC%=E)dZ!_Mkz4Fb#DWsV$|HOosc*OsOugE?-guuI8(Yl!En9!~^YBTro<4UkQN-=^ z8I!ipmrm#J|N2w>{;b-QtW&x+D#UzLT-DNYqbB-IerMQ*f;Zh?XH2``RI>8(#CPxH z&i7Q$v$wS MBQ`1h3C!y2vROZYy?4Jv`^IE2r+VH&51{ zIIDf~&-eI$9}T`{7=HWq+3mV3%gaZ};VXkgPtFQm&BT)3ZO9(TDJDLdfx+(nq8z=X zqLrT~mf!zh^j*6CXGPTR!#<7w!h({fL`jJ*2s<&^L{9FJoQww7!A15d7T=B*`ON*7 zRJii9;4;>3wqMbnZAONgiXl@oG=z_4H4AJ>cz8qnwPESX$tAxg7p?r IcxJy1qKylWK6{Su0-rnbN YV!X*ES!$WBWM%ils8dzWVbt;$7#LrbWAY4k_*Z zlyqFx{*~!!hk9*I!ysARkKxO;CYd*zLOVli%XL $1`AZOYlmn?H8^6!z0qJaB(`+`^7P$20C6e|6(H#P&)bh@P^xIeYppB}F6m z6O)5?rsd?E*|=v<)H3bW{`y+${FJXwS)Oe7;C|G6nVDyw&)|RF#JYQx@~&^WJ5zI` z3*L067Ca4V?-Y5hdU|v2(WQP}|Nb#vKeQ;wHL H^%R!cKy;4J;B@c`fjLx35ofx+;-&5O! zLwu!?;GIwVYZGr9*VuSI3E9w !}UkbDo48dE_Xb2ZqqBh&G;+&xPM5#UhBqt zqRY?h;yD~NrChD<*D3G)Hx6!}C$_xl>z)5uS9jeyXYy*I=nMXt5_y4aJBn6b_N$LB zUs=q0_kNS)2iMlCr#|bxJ$OY(+adn-gWdX?3EN%wK4P82DQ40kf9jO=*|g*cpFjbP z|2s-nb{~AH&$eLy)Y;(^;^Hdxc+;{sW;R!pJ^x!hzxEen+})V7GZP#oKfjSL*4-6Y zZgoVA_2HqVe)AVB@}4{2p >e_OX~>awzw{;S(+qxM_>cUgK+{~m{srqoxg zLWkRV$`*bpO<5BAD#_AO)cUFD)lHW!U4E(F^(E8ic+HZ)g+JNvS9jiMXq>6Qbx>%w z_=zh^{XSV4m8|3zevvOKGEK`%Tk6uMPp6D#cKuwCF!R8agwD)2+yS1wm2T6mlJqXz z|E2c)# (GgxFs&j+)!gh`Bg_1tIuXy%Vx=r6@VOjkx#v|`u=a)y9 zj`3tC*=a$P> zbxp1C^y#^p=jET4TW2HA5wu~B_zmuROY2_jZi}tAzc%&j%kuPj%7QB!Kk4h83I3e$ zsA;dY8EZ+4^<08dO(HrAnV#Oa-*+j`dPUyN&lk L*40HZnd@9fBFFK|EwQ}tyd9Sitzi*rmOK%Kiv<>Z$a5$JGc_XrR&E83@ zPvyUMg&tU%r}O{am$OaHoIO_*l9*V#T_31?*!;&^f099i)6ee*jxG4xpBFKW^{KpD zmVjYX(@`bfwSR>UpX<8%)Ad2neTm1vC8yN)- B@uO zi>3* ^ DbLP!_a4g87t7!4-KenX^p|rYvh8Mj2#DI e|5JwDmbyS zb{lNC-Lyyk$-e|2!yfH68-=ZBq%PdQbhSid;eJ-Lj`~b4c?W40C6j;+7EFEui6BLF z3I`MQd-T<=-Z#3X(Dyy{po8NE$Ao%rK`xC58Ro}b^Y2t$x08tH`K!CFHrm9%ecm=l zhkEXHhnG(iXxY9X;Uf!3Zf(2hyXwR>hMdwY3}zh3^{;oEE#_tV9nCS{@!%uD3-^Om z+@2kXNZ#OhV2*YWr~}-<%am*fmQ^&kCXpjx@SN*cbV9Sj#rsUsEXQgD?3$a7CMTQ| z{j$AogCooP_Sd^ssD>S!!G9<`U;_)o4TT5O(sr!l&JmFK?3g1eqSMG=#(~0TG~?*` zsj!WUYnsEs8T?7z3lcabKmu%B(>M;y;7`(CkkHv7oou%xM_`%ZeCPY7Zw}4iKP09R zq14j%6YRK-84d@9G%tYM^Ku6Nluq+wH5+_fW-zgOKbdi?CPSL#
CR;v*Qc~*3)eZas`$d$_s^0xU2K5*^J|eP{4*9fy*<_H+ORH==@o8 zx4}^UNKU|p9ElB%HlUncDEOHX?Dt~FgHClqpA}P^4SIjpd^w+AzKEA;CZCATkrSnc z^HbD68P0E7E%DiL8Dw}Wzmd18 }Bq*A*CfjkyJ05h(;|2v~V^gaS zh_SDssr3vf6k?j2T4(UaC)q`)-I6QbylK-4{gan2em=Z^)|JJPF0B<$r2kzG>Nh)j z N(i^K(kJOKC0s zne=<%G*-WLi}(Ir9H*Q-+3(8s4TrYAU;gI7dq3ynQ{J5VV0!-DH@EQk_e*sHwgug9 zno)33;nmIfr;%SQKY#m_aq>)n%o4du(0EKnj*a}MqtlO<)h*Vmvj~qa&7b)0N~~yT zue9`RE7h;OYcE~fb}qD;dAe-)k6&AE+`Q= 0n{zOu8QqMlvLGcVVhXumzc;b0Pnh|cE~YgbR- zQ~u%g{lA|-TvR`2zP+7?k9T+6?r(boMIO9f_wL?P_3U$}qN4R%zkKK2<=@kP=94MM z^pEDk2@^jb+E==;@#(#F!C%*{^V=&tIk<27x*nb7(;}IrK5u 8d_eO224A>yS#G3ugVdwVu`tAR|+`agyI& ^RAlmZu-`DFZ6Eg+I8Jx zJHO~hZrafvl_o3D{b8ziNw;iU^qsqRsuuXL1TLHwx%jq1U#aijO{WhBpWdx^Ww%~o z=}T5&ovk^W7bF<6a9um|Gid7XAMW#ID*LMDhzXef=&pKIviePs|Nl?g(|6BF*zUS% zzvzZTs|~N*cQyb2+dH; BLW(1 +6e(`%Uju6@y=Fn9LjtIty9 zyl=I;tHtW`_f!R)UUSjj Rvm8g CY#nHD?&g)xR{I(zdGpX 2v5n0g>*nS^U#=)WZdm?$aeu$f_j8TwH`)DrazgJzb)dIPL+0{j zhVu6Q&yBALX&;z!IruEI#iYmu3lcaRe!utqtu4J3g4V zK3|pl;P0Yok?f~jewod0zowt`*KGc*Vq1*}CRSE&h9#$#YPH(9x!P_z_TWP3^*ehm zo%zm}wdvolbK=!SSB@KbOzTYeawb4cHtDySyo8WPZ6^nhhz{e1jEUa&``pd;E}L*X zZS&5{i+0|)`1b!#`~9`Q_A=j3*<1gh{h!!Ymlo;#&z!L@!<=*toA%y~;ql@Y`I5-V z!r#AiuJ*LuSM?)y6ztfae`4?Y`!&idcixfs{P9D ?z# {qDwJy}p36q?ob8ObNk_QP1CP+i>)3t*3v! z|9tT|-vUpsVf?&(!G6}u3cGgSigh&c{I-38A^%_9=R5ztHF#U{;nk5x(O 6 zw(QOSqr3lDMv4_qsmc|Gm|E-*xy|UndPAk0spm2u&RM7GedpH#pBAIOUt(bmMj}1S z)6Z@5cHF_nRwcW4kL_*GZ`)sFF7JN+b-P3T>C8skBQ Hs8J9bj<$C_H*Xtt+6lVOXlw~ zv*T3nTJkG8K<(1swGB%*f35RYTXp#Fo6pHj;+faH_k^xA)DGPi!Zxc3Z0Z}vr87;U z7Dc~$cID0Et!ru%KCIGCVPBbgtzl+t>GD}i5}F$f&whTB&OiBGzT--cN38!3zT;ja zxb0HHe#s z3uZWU)@_H+rR8B>-IgHFEd>`zOz8~v*Qs?Pz}EHW^=Te{EeSK&TpP~W8TkQ zCRMq1;)e6PPG#}PDT_5Xr6#wuuDxjg=R@r8d3OrSuU%s|f6M>jb7JWnZr@tx%`NlF zer+$eyW?7QOH+vtRM%?=FWmq2NZ*-o`P=L6%r4yih}qmc{Mxad7cN}( #{8SNGCoKf#BMO|5@AOseMc z ozzR6wc;Xk_p%_;dR5mYi(Da%t@cW>wHFYz`dD2 zBsry7zHC3h=6L@Zvl+*md_{A}WLdssu7H0^T5f&H
Lto71A3OHhqFvVUpi^2~<{9=JfhEayTR_df zZMe*5$5}yV6G$J_icSN3PpTc{{ v*YIlGY$*iBSI6c z12zaaCP{t1`Rl>5ze|$r3TAPrD$P?WV&)Q4$~eIG@kpP~B13r%LGJF=Q?DpH35e*p zd}shQ6V }uv?jW%ro@J$`$&8O(6fV9Xcrx)V9H>Wt!riGiCLhzmm%HdVWr+ z0y~03Y{uDtAJyIKbp9)B@zLGLb|>rak-jt65AN{V>jZKo2Oo!`vxMZS{pI)U_eh_z z&*}_Kh+?^uHTPrjQN~xIP7)$IE(Q)i*^O@~w(umT%sA_JD2_o@!Kbq!Q?OvQDa*!{ zsx1Z@5giH*2Mo_FYm$5;;FR|I%XyI*Y>ewF3(g;&!ZAb4QCCr>v8nZg)CSE1Q$Gt> zwA~CbXr3FDBwBE?Ia)5}^MiTqnu1q^4k $G4|jiS%$^q|q+)9u?(#KKa7jYwyqA8J?!@}Hl7JvzMiilE)&S0 Bo($H(kDLF4x9jx>d#FMRVt-F1J+2g>jj_>;0ufXVrh$JH2Dhfpa1Uxx{*x z-#(O9d8KITk^F5|aZ Y?(zvbm?ZIQy1;%vNe13{)db5*zb&-MEmNmAPQCnwE`+`(C#S zo;Pd?OKSG4P}_WAgS0~8AC?1uW=;`U>DR-5($A;kY;$GQl}QQ<%a=|4#eM41r>J8} zo*=VyBN{;S|0_&SZ+UpSjVCoJ=UdVHrA_zlbxRhkl(!F@TDZt#y-MnzmQVU>Rw2^z z+pVlkO)cGDJe7arbCqr3s+HN(H*Yj{J!rIW+e-IuN3`9$SGv13{tN3`=o7QOCP>$R zLdJ&uN97kt&RO32>HVHf3pNCKuKL3~y=v3L_f9!)X36X@>#5T9NJx*02$>cXb#cL& zv%05KPETet7yf(x_5M3fwx5{Jv8>*`{QT#8_v>!k*!|qg{I#nPbK3sh0{awJ*V38S z%$m %YX6ZIk5Z?Y05gj#t$BZ1 z>_q4M3w<%0*ZQ)S>TUHE7oJytUwi-LPq9zWLN;`re*NVC*NZp(_4#}B7RPO5`?CF! z@}8>?=Y{j8CM{w69sS1nm$MtQ-q#y1F8uj=@--j#-5;4%O;v{ioF;!*(s;vupY7+b z@iv=N`M-9V7idKsP@i@AeEpQ-XRJbtSa >n?pag?Z0y4ev;fR?vRL> z`JS(w*&Kc@4>+>ontIFXC6`LA6sOn6%w5nF;dtTq$G4K}KNW_b+L_SX+iP9-PycP- zqT(|CE2dvh+<22YQ)o-l#yGK8EBj(Hmmm8lR@~sd_tz6k%iy>LGa2+sHU2MBW;U69 z$y`QkmoKB&i%XY+GgbTp7;jDgcEWk~w~t#}p2cj)SYWfp#(ZX7%>8K>K~u4N(?m6d z4~OlP{u^z$S}beB{#47D-B*G|Pg*+3uVS}9yy(%UDNc81p4qf1%5tS}$c>rDJPvPh z`mpq)+lGe5gNfJo99s3|)wasaUAOpDR~iZC2wcpbmbtWUvepJiozmi?DgSsLo?0sR z;CZo|-t@HYgG=+GoTf{)bY0 VnsX+3W<~Z3x$bp);$}_{pXPaMsa|i?O3zT0ryP6#JYLko)>36~ z(EH$`mDZPaG%b)8J5-&ux^UlXQpHNMqgAyH%RB9lURmn5>5uSaZ`r!Got5gBJf>Y> zc;h21bbV!OmBGR6gG>uF<0Fg1mSszvKC?dS{F^tj-xh;cvy>nCS^KLb?L&8j(mw`S zR>ikL?P(v_Dt)#|#Jq~J{Cjkh@zcEt7ai)o=Z5dvxv$#s)W=oZ&MchR>3T(Iwauh` z&$h hZ}&=fuXLY%;7f;W?5k;x(Y7<>ejCYdX*4sl@=$L3vqZB=REObL zwCmH-u1UvE^2FvYpS1R0Sj>#&Y5(<~dc6v~Qc!wCPi?x@?d15p)*C!q%$+YZxiU|d z-{J~h^l;f>$BcLRu56W0_HVVG8eZIZqv2)eRAWaUd81pe7z?E)?X}w|nUUYF!P33# zV@ 7`&hQI3>o}!}6|#B*wE8Hp za#?hqZ~g0~b3gLmlYIVN^Q%V1g{676F+H`63tFam9o~{;>1Zl`kxPvCh60bZo@-@y zEZdoh=G*s+?z*%#<^DRBr#{Cn@Wj3P_{OeW?}u0Q?2Y9QUp%_>{L#C6Pxq$v-s@BU z&$P( Rl~ ?I9M70M+kE8c#@E;T-R#$P zd v_vO4n)T8Bs&U4y4 zbAmQxIP6#ulC$@QEW>#Nzhl>LKmN0dVg9d~U)CHutu?iF{obmKtcr?b{~z7*UTk`< z{zt9aY+K!RF|SHQTzK?KWqu#>&xzWwW@-L=?^PR 0QZ7aJh zriQ36bKYcQJ?*q^%l6;>_Wzz#zPhOMX7OT^?)b`?6LXZN>y=t0#qYQKv|&Q*s~B0Y z3t{~lC%Js9ejPh}WBDvejR-NLi&s>3{^_n?y-4otAv+tJ`j7MDwrlM>$Uc471#fYg z-%2(C8+2IqgfmCWzno)gm{=BfvGDORezCvD^|uH2r!n&;UOMJ#I8`sEuU7E#)}JvA zO{uKY=U2y>2i6~Z6B(nozpC!|AM1A(9=7Ks^rQ|YX~piiHFegvUpa<;hgCEp!VErr zHTUP=^YdBsmB&3ZUO&8O^n8E(H2uhZHOJ&@N>)a*%PxQTNGvs4^0yP0h>o_zo|2Qr zkNp3CetG2NteJOT80X)c@j3Z+e9VT*&vviQ=03c%)GvOGX32D`zFI+Xjfk*IAwf#< ze~wO%yxe*1O)K~B=lOSjG~T_&{{2k(%zgh4yE@M(i)i+a)ez6V$EA0CUx(|PpB!9b z%nccpQ>Nrfu3tahcb;|m-9NelS{+Z$^iRoBGe5;|p&wgy`ycCHM{PaJ*`Aveb;PDy zO*!xCx>Pe^-qWl%-4~9|I}hs4Pifb!s{M2H^789PZ{OZsXK(VxDt}^hdh6Yg>ECZ{ z4XqREd{ $|4m{%q9x%~XQxxRV@J&O$XpQYPhtH{bF#@+Cg@n5mwn`LQ} zBwI2W -+h^Y2VQz5WZ^!=xvCM{f(Fu6=0w@!+Cfy Qv-as$HB=qdYU59e_wkuw7AUsHtE2zq_otci zZQ9fAzpN~H!(H!q@DbzIt;9hDw zi_dB72d~}`H@y2nIV@m9#i5& tq)O@KT100ZJ=_ zMLng=yj1j#@4K*F tV!t_NiZ;0=4joh&yfs;jJJ{Om_=u%PMOo2)JZWNyEk4h4Kk$+Um?nU4v z(N`r;+j6{f1(qepd)%AJQL82MTS+cp0}I=i?fXtzZrk}Sq}nSlj#EOj^M=BL{aY17 zmvQlby{N@|D7BBbX`e~+lN;g;k4!ASxyCF=;1qe0|MZE>-I$nLGYU67)9DFOymsHq z*Yw=^Aa%7PPwubV-@08x*{8WlwSbG;`{`Bn^O}8`r;W~;n8cgEo#Lx>sJTSov!`F& z^xEVz?8o;h ^GhGUo*@0w_$!5r7HG{)neU~u`NhPUjZLafKFM|}zoS(I zPwP}2u?g7V!X^9p;?%3l#YMxHPkfWVk@JQ~!JF>4O--sr2iO85LRM+$tUIqD`8iSQ zvITEn?Z()E4LK}U&w>}`8-Cl~5~B7<_Y?;&*R)>7&D;CtuecWz6*%3gsHa!;!42^z zZlLj`b;oX;5s~@bbcahsNBUSv5AVqt=hrUy9g?)eSTK=YMCZxz8U9QEIZ2%~G+Q>K zulAq?Z;^Juh6(ZylX`gjY8}rof>tvJCFi^VSr6fAevyziOR}rzHcHaeh&YkkIKw~h zUT2Bgu^SI=h#!dx*f2pd@vMZjm0xpmyg)W+2&ZRfa?S#OaNsvJwa(zRJ+^Gcl7j(i zW+(E_s9&nndJ+6k_Y}wE1qq5`%!cznb-nu0_wM0?g$D&6hXhtv?+y%~ZmD}I!_)BF zN`YmL2c6ci`H4IXllgJ$qC$YgQpX!i;3e(`?Y~4F1zNt7vl?C??d-4r{c9vV6C{%3 R85kHCJYD@<);T3K0RZxem7@Rv literal 0 HcmV?d00001 diff --git a/web/src/App.tsx b/web/src/App.tsx index 0c54f7ff..769ac63a 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,11 +1,10 @@ import { RouterProvider } from "react-router-dom"; import "./App.css"; -import { AuthContextProvider } from "./context/auth_context"; -import { MessageContextProvider } from "./context/message_context"; -import { router } from "./router/router"; +import { AuthContextProvider } from "./core/context/auth_context"; +import { MessageContextProvider } from "./core/context/message_context"; +import { router } from "./core/router/router"; import { ToastContainer } from "react-toastify"; - function App() { return ( diff --git a/web/src/components/admin_panel_navbar/admin_navbar.tsx b/web/src/components/admin_panel_navbar/admin_navbar.tsx deleted file mode 100644 index 81e61e3d..00000000 --- a/web/src/components/admin_panel_navbar/admin_navbar.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faEye, faEyeSlash, faSignOut, faUser, faWindowClose } from "@fortawesome/free-solid-svg-icons"; -import { Link } from "react-router-dom"; -import './assets/styles/style.css'; -import { UserRole } from "../../constants/roles"; -import { useUserData } from "../../hooks/useUserData"; -import { Dispatch, SetStateAction, useState } from "react"; -import { useAdminChangePassword } from "../../hooks/useAdminChangePassword"; -import { usePasswoordVisibility } from "../../hooks/usePasswordVisibility"; - -interface props{ - isWindowActive: boolean; - setIsWindowActive: Dispatch>; -} - -export const AdminPanelNavBar = ({isWindowActive, setIsWindowActive}:props) => { - const {user, handleLogout, setToggle, toggle, userData} = useUserData(); - const [changePasswordWindowActive, setChangePasswordWindowActive] = useState(false); - const setChangePasswordWindowVisibility = (visibility: boolean) => { - setIsWindowActive(visibility); - setChangePasswordWindowActive(visibility); - } - const {register, handleSubmit, errors, onSubmit} = useAdminChangePassword(setChangePasswordWindowVisibility); - const { - values: valuesPrevPassword, - handleClickShowPassword: handleClickShowPrevPassword, - handleMouseDownPassword: handleMouseDownPrevPassword - } = usePasswoordVisibility(); - const { - values: valuesNewPassword, - handleClickShowPassword: handleClickShowNewPassword, - handleMouseDownPassword: handleMouseDownNewPassword - } = usePasswoordVisibility(); - const { - values: valuesNewPasswordConfirm, - handleClickShowPassword: handleClickShowNewPasswordConfirm, - handleMouseDownPassword: handleMouseDownNewPasswordConfirm - } = usePasswoordVisibility(); - - - if(!user ){ - return null; - }else{ - if(user.role !== UserRole.ADMIN && user.role !== UserRole.SUPERADMIN){ - return null; - } - } - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx b/web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx deleted file mode 100644 index 94aa6d31..00000000 --- a/web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import DataTable, { TableColumn } from 'react-data-table-component'; -import { usePlace } from '../../../hooks/usePlace'; -import './assets/css/styles.css'; -import { Place } from '../../../infraestructure/entities/place'; -import { LoadingSpinner } from '../../loading_spinner/loading_spinner'; -import { faEdit } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dispatch, SetStateAction, useEffect } from 'react'; - -interface props{ - idTown: number; - isWindowActive: boolean; - setWindowVisibility: (visibility: boolean) => void; - setActualPlace: Dispatch-- { - changePasswordWindowActive && -{ - isWindowActive - ? - setToggle(false) - : - setToggle(!toggle) - }} - style={ - isWindowActive - ? - {cursor: "auto"} - : - {cursor: "pointer"} - } - /> - {toggle && -
-- } ------
{userData?.name}
-
- - {setChangePasswordWindowVisibility(true); setToggle(false);}} className="sub-menu-link"> -- Cambiar contraseña
- - - -- Cerrar sesión
- --- } -- Cambio de contraseña -- -setChangePasswordWindowVisibility(false)}/> - - -->; - setIsRegisterPane: Dispatch >; -} - -export const AdminPanelPlaceList = ({idTown, isWindowActive, setWindowVisibility, setActualPlace, setIsRegisterPane}: props) => { - const { - placeList, - pending, - updatePlacesByTown - } = usePlace(); - - const handleEditSelectedCategory = (place: Place) => { - setIsRegisterPane(false); - setActualPlace(place); - setWindowVisibility(true); - } - - useEffect(() => { - updatePlacesByTown(idTown); - },[]); - - const columns : TableColumn [] = [ - { - name: "Identificador", - selector: row => row.idPlace || 0 - }, - { - name: "Nombre", - selector: row => row.name, - sortable: true - }, - { - name: "Estado", - selector: row => row.available - }, - { - name: "Acciones", - cell: (row) => { - return ( - { - if(!isWindowActive){ - handleEditSelectedCategory(row); - } - }} - /> - ); - } - } - ]; - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx deleted file mode 100644 index 8250307c..00000000 --- a/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import DataTable, { TableColumn } from 'react-data-table-component'; -import { usePlace } from '../../../hooks/usePlace'; -import './assets/css/styles.css'; -import { LoadingSpinner } from '../../loading_spinner/loading_spinner'; -import { faEye } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dispatch, SetStateAction, useEffect, useState } from 'react'; -import { usePointOfInterest } from '../../../hooks/usePointOfInterest'; -import { PointOfInterest } from '../../../infraestructure/entities/poi'; -import { LoadingScreen } from '../../loading_screen/loading_screen'; - -interface props{ - idTown: number; - isWindowActive: boolean; - setActualPoint: Dispatch- } - columns={columns} data={placeList} className="data_table"/> - >; - setWindowVisibilityViewer: (visibility: boolean) => void; - setBinaryData: Dispatch >; - setIsPDFViewerActive: Dispatch >; -} - -export const AdminPanelPoiList = ({idTown, isWindowActive, setActualPoint, setWindowVisibilityViewer, setBinaryData, - setIsPDFViewerActive -}: props) => { - const [isLoading, setIsLoading] = useState(false); - const [isPDFLoading, setIsPDFLoading] = useState(false); - const [printButtonActive, setPrintButtonActive] = useState(false); - const [selectedRows, setSelectedRows] = useState ([]); - const [actualPlaceId, setActualPlaceId] = useState(0); - const {getPdfById} = usePointOfInterest(); - - const handleRowSelected = (selected: { allSelected: boolean; selectedCount: number; selectedRows: PointOfInterest[];}) => { - setSelectedRows(selected.selectedRows.map((element)=>{return element.idPoint || -1})); - } - - useEffect(()=>{ - if(selectedRows.length>0){ - setPrintButtonActive(true); - }else{ - setPrintButtonActive(false); - } - },[selectedRows]); - - const handleClickPrintButton = () => { - const fetchPdf = async () => { - setIsPDFLoading(true); - const res = await getPdfById(actualPlaceId, selectedRows); - if(res!==null){ - setIsPDFViewerActive(true); - setBinaryData(res); - } - setIsPDFLoading(false); - } - fetchPdf(); - } - - const { - placeList, - updatePlacesByTown - } = usePlace(); - - const { - pending, - updatePOIByPlace, - poiList - } = usePointOfInterest(); - - const handleViewSelectedPoint = (point: PointOfInterest) => { - setActualPoint(point); - setWindowVisibilityViewer(true); - } - - const columns : TableColumn [] = [ - { - name: "Identificador", - selector: row => row.idPoint || -1, - sortable: true - }, - { - name: "Nombre", - selector: row => row.name.substring(0,40), - sortable: true - }, - { - name: "Acciones", - cell: (row) => { - return ( - { - if(!isWindowActive){ - handleViewSelectedPoint(row); - } - }} - /> - ); - } - } - ]; - - useEffect(() => { - setIsLoading(true); - updatePlacesByTown(idTown); - setIsLoading(false); - },[]); - - const refreshList = (idPlace: number) => { - updatePOIByPlace(idPlace) - }; - - - if(isLoading) return - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx deleted file mode 100644 index 25b25c85..00000000 --- a/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { faWindowClose } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useEffect, useState} from "react"; -import "./assets/css/styles.css"; -import { languaguesList } from "../../../constants/languages"; -import { LoadingScreen } from "../../loading_screen/loading_screen"; -import { usePointOfInterest } from "../../../hooks/usePointOfInterest"; -import { EmptyPointOfInterest, PointOfInterest } from "../../../infraestructure/entities/poi"; -import { ImageDropzone } from "../../image_dropzone/image_dropzone"; -import { usePlace } from "../../../hooks/usePlace"; - -interface props { - setWindowVisibility: (visibility: boolean) => void; - idTown: number; - forceRenderList: () => void; - isRegister: boolean; - form?: PointOfInterest; -} - -export const AdminPanelPoiRegister = ({setWindowVisibility, idTown,forceRenderList, isRegister, form}: props) => { - const { - register, - errors, - setDescriptions, - setDirections, - descriptions, - directions, - setLanguageDescriptionIndexSelected, - handleSubmit, - onSubmitRegister, - getPointById, - setValue, - languageDescriptionIndexSelected, - languageDirectionsIndexSelected, - setLanguageDirectionsIndexSelected, - } = usePointOfInterest(forceRenderList, setWindowVisibility); - const [isLoading, setIsLoading] = useState(false); - const [preview, setPreview] = useState- Lugar - - ---- { - isPDFLoading &&- } - onSelectedRowsChange={handleRowSelected} - columns={columns} data={poiList} selectableRows className="data_table" - /> - - } - (null); - const [image, setImage] = useState (null); - const { - placeList, - updatePlacesByTown - } = usePlace(); - - useEffect(() => { - if(image){ - setValue('image', image, {shouldValidate: true}); - } - },[image]); - - useEffect(() => { - setIsLoading(true); - const fetchData = async () => { - await updatePlacesByTown(idTown); - if (!isRegister && form) { - const pointGetted = await getPointById(form.idPoint || 0); - if(pointGetted){ - setValue('idPoint', pointGetted.idPlace); - setValue('name', pointGetted.name); - setValue('contentEN', pointGetted.contentEN); - setValue('contentES', pointGetted.contentES); - setValue('directionsEN', pointGetted.directionsEN); - setValue('directionsES', pointGetted.directionsES); - } - } - }; - fetchData(); - setIsLoading(false); - },[]); - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx deleted file mode 100644 index 48c0763e..00000000 --- a/web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Dispatch, SetStateAction, useEffect, useState } from "react"; -import { AdminPanelPoiRegister } from "../admin_panel_poi_register/admin_panel_poi_register"; -import "./assets/css/styles.css"; -import { AdminPanelPoiList } from "../admin_panel_poi_list/admin_panel_poi_list"; -import { Town } from "../../../infraestructure/entities/town"; -import { PointOfInterest } from "../../../infraestructure/entities/poi"; -import { AdminPanelPoiViewer } from "../admin_panel_poi_viewer/admin_panel_poi_viewer"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faWindowClose } from "@fortawesome/free-solid-svg-icons"; - -interface props { - isWindowActive: boolean; - setIsWindowActive: Dispatch- Registra el punto de interés --setWindowVisibility(false)}/> - - {isLoading - ? --- : - - } - >; - town: Town | undefined; -} - -export const AdminPanelPoiScreen = ({isWindowActive,setIsWindowActive, town}: props) => { - const [renderCount, setRenderCount] = useState(0); - const [isRegisterPane, setIsRegisterPane] = useState(true); - const [actualPoint, setActualPoint] = useState (); - const [isRegisterWindowActive, setIsRegisterWindowActive] = useState(false); - const [isViewerWindowActive, setIsViewerWindowActive] = useState(false); - const [isPDFViewerActive, setIsPDFViewerActive] = useState(false); - const [binaryData, setBinaryData] = useState(''); - - const forceRenderList = () =>{ - setRenderCount(prevCount => prevCount + 1); - setIsWindowActive(false); - } - - const setWindowVisibilityRegister = (visibility: boolean) => { - setIsRegisterWindowActive(visibility); - setIsWindowActive(visibility); - } - - const setWindowVisibilityViewer = (visibility: boolean) => { - setIsViewerWindowActive(visibility); - setIsWindowActive(visibility); - } - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx deleted file mode 100644 index e06694a0..00000000 --- a/web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import { useEffect, useState } from "react"; -import { PointOfInterest } from "../../../infraestructure/entities/poi"; -import { usePointOfInterest } from "../../../hooks/usePointOfInterest"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faWindowClose } from "@fortawesome/free-solid-svg-icons"; -import { LoadingScreen } from "../../loading_screen/loading_screen"; -import { languaguesList } from "../../../constants/languages"; -import { usePlace } from "../../../hooks/usePlace"; -import './assets/css/styles.css'; - -interface props{ - pointId: number; - setWindowVisibility: (visibility: boolean) => void; -} - -export const AdminPanelPoiViewer = ({pointId, setWindowVisibility}: props) => { - const [point, setPoint] = useState- Administrar puntos de interés dentro de un lugar - --- { - isRegisterWindowActive &&-- } - { - isViewerWindowActive && - } - - { - isPDFViewerActive && - -- } ---{ - setIsPDFViewerActive(false); - setBinaryData(''); - }}/> - - --(null); - const [isLoading, setIsLoading] = useState(false); - const [languageDescriptionIndexSelected, setLanguageDescriptionIndexSelected] = useState(0); - const [languageDirectionsIndexSelected, setLanguageDirectionsIndexSelected] = useState(0); - const [descriptions, setDescriptions] = useState (new Array(languaguesList.length).fill("")); - const [directions, setDirections] = useState (new Array(languaguesList.length).fill("")); - const [placeName, setPlaceName] = useState(''); - - const { - getPointById - } = usePointOfInterest(); - - const{ - getPlaceById - } = usePlace(); - - useEffect(()=>{ - fetchData(); - },[]); - - const fetchData = async () => { - setIsLoading(true); - const result = await getPointById(pointId); - if(result){ - setPoint(result); - const newDescriptions = descriptions.map((element, index) => { - if(index===0){ - return result.contentES; - }else if(index === 1){ - return result.contentEN; - }else{ - return element; - } - }); - setDescriptions(newDescriptions); - - const newDirections = directions.map((element, index) => { - if(index===0){ - return result.directionsES; - }else if(index === 1){ - return result.directionsEN; - }else{ - return element; - } - }); - setDirections(newDirections); - - const place = await getPlaceById(result.idPlace); - if(place){ - setPlaceName(place.name); - } - } - setIsLoading(false); - } - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/admin_town_info/admin_town_info.tsx b/web/src/components/admin_town_info/admin_town_info.tsx deleted file mode 100644 index 22b72931..00000000 --- a/web/src/components/admin_town_info/admin_town_info.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { Dispatch, SetStateAction, useState} from "react"; -import { Town } from "../../infraestructure/entities/town"; -import "./assets/css/styles.css"; -import { faEdit, faLanguage } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { LoadingScreen } from "../loading_screen/loading_screen"; -import { useAdminTownInfo } from "../../hooks/useAdminTownInfo"; -import { SuperadminPanelTownRegister } from "../sa_panel_town/sa_panel_town_register/sa_panel_town_register"; - -interface props { - isWindowActive: boolean; - setIsWindowActive: Dispatch- Información del punto de interés -- {isLoading || point === null - ? -setWindowVisibility(false)}/> - - : - -- } ------ Nombre del punto de interés -- --- -- Descripción del punto de interés - -- { - languaguesList.map((language, index) => { - if(index===languageDescriptionIndexSelected){ - return ( - - ); - } - }) - } --- -- Direcciones hacia el siguiente punto de interés - -- { - languaguesList.map((language, index) => { - if(index===languageDirectionsIndexSelected){ - return ( - - ); - } - }) - } ---- Nombre del lugar al que pertenece el punto de interés -- ---- Nombre del punto de interés -----
>; - town: Town | undefined; - updateTown: () => Promise ; -} - -export const AdminTownInfo = ({updateTown, isWindowActive, setIsWindowActive, town}: props) => { - const { - isEnglish, - isLoading, - setIsEnglish, - setIsLoading, - renderCount, - forceRenderList, - statesList - } = useAdminTownInfo(updateTown); - const [isTownRegisterWindowActive, setIsTownRegisterWindowActive] = useState(false); - - const setWindowVisibility = (visibility: boolean) => { - setIsTownRegisterWindowActive(visibility); - setIsWindowActive(visibility); - } - - if(!town){ - return ( - - No tienes un pueblo asignado -- ); - } - - return ( -- {isTownRegisterWindowActive && -- ); -} \ No newline at end of file diff --git a/web/src/components/confirmation_dialog_box/confirmation_dialog.tsx b/web/src/components/confirmation_dialog_box/confirmation_dialog.tsx deleted file mode 100644 index 9cc98917..00000000 --- a/web/src/components/confirmation_dialog_box/confirmation_dialog.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Dispatch, SetStateAction } from 'react'; -import './assets/css/styles.css'; - -interface props{ - hangleToClose: () => void; - setAnswer?: Dispatch- } - - {isLoading && ---- } - -- --{town?.name}
-----setIsLoading(false)}/> -
---- { - isEnglish ? - - : - - } - - {town.state} -- --- { - if(!isWindowActive){ - setIsEnglish(!isEnglish); - } - } - } - /> - { - if(!isWindowActive){ - setWindowVisibility(true); - } - } - } - /> - >; - title?: string; - message: string; -} - -export const ConfirmationDialog = ({hangleToClose, setAnswer, title, message}:props) => { - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/image_dropzone/image_dropzone.tsx b/web/src/components/image_dropzone/image_dropzone.tsx deleted file mode 100644 index cb55cf7c..00000000 --- a/web/src/components/image_dropzone/image_dropzone.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { toast } from 'react-toastify'; -import { useDropzone } from "react-dropzone"; -import './assets/css/styles.css'; -import { Dispatch, SetStateAction } from 'react'; -import "react-toastify/dist/ReactToastify.css"; - -interface props { - setImage: Dispatch--{title || 'Confirmar acción'}
----- -{message}
-- - -->; - preview : string | ArrayBuffer | null; - setPreview: Dispatch >; -} - -export const ImageDropzone = ({setImage, preview, setPreview}: props) => { - const MAX_SIZE = 10485760; - const {getRootProps, getInputProps} = useDropzone( - { - multiple: false, - maxSize: MAX_SIZE, - accept: { - 'image/jpeg': [], - 'image/png': [] - }, - onDrop(acceptedFiles, fileRejections) { - fileRejections.map(({file, errors}) => ( - toast.error(errors[0].message, { - position: "bottom-right", - autoClose: 1500, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: false, - draggable: true, - progress: undefined, - theme: "colored" - }))); - - acceptedFiles.forEach((file)=>{ - const preview = URL.createObjectURL(file); - setImage(file); - setPreview(preview); - }); - } - } - ); - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/loading_screen/loading_screen.tsx b/web/src/components/loading_screen/loading_screen.tsx deleted file mode 100644 index 42c89426..00000000 --- a/web/src/components/loading_screen/loading_screen.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import './assets/css/styles.css'; - -export const LoadingScreen = () => { - return ( -- - {preview ? ( --- ) : ( -
Arrastra tu imagen o seleccionala dando click aquí.
- )} -- -- ); -} \ No newline at end of file diff --git a/web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx b/web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx deleted file mode 100644 index 9b0eef09..00000000 --- a/web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { UseFormSetValue } from "react-hook-form"; -import { Place } from "../../infraestructure/entities/place"; -import { useDropzoneMultiplesImages } from "../../hooks/useDropzoneMultiplesImages"; -import "./assets/css/styles.css"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faTimesCircle } from "@fortawesome/free-solid-svg-icons"; - -interface props{ - setValue: UseFormSetValue; - imagesList?: File[] | string[]; -} - -export const MultipleImagesDropzone = ({setValue, imagesList}:props) => { - const { - getRootProps, - getInputProps, - imagesFiles, - removeImage, - } = useDropzoneMultiplesImages(setValue, imagesList); - - return ( - -- ); -} - diff --git a/web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx b/web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx deleted file mode 100644 index f4ca3657..00000000 --- a/web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import DataTable, { TableColumn } from 'react-data-table-component'; -import './assets/css/styles.css'; -import { LoadingSpinner } from '../../loading_spinner/loading_spinner'; -import { useState } from 'react'; -import { Admin } from '../../../infraestructure/entities/admin_form_values'; -import { State } from '../../../infraestructure/entities/state'; -import { useTown } from '../../../hooks/useTown'; -import axios, { AxiosError } from 'axios'; -import { showErrorAxios } from '../../../utils/Messages'; -import { useAdmin } from '../../../hooks/useAdmin'; - -interface props{ - isWindowActive: boolean; - statesList: State[]; -} - -export const SuperAdminPanelAdminList = ({isWindowActive, statesList}: props) => { - const [isLoading, setIsLoading] = useState(false); - const { - townsList, - getTownsByState - } = useTown(); - - const { - adminList, - getAdminListByTown - } = useAdmin(); - - const columns : TableColumn- --Arrastra tu imagen o seleccionala dando click aquí.
-- { - imagesFiles.map((image, index) => { - return ( ---- ); - }) - } ---{URL.revokeObjectURL(image.preview)}} - /> -
removeImage(index)} - /> - [] = [ - { - name: "Email", - selector: row => row.email, - sortable: true - }, - { - name: "Nombre", - selector: row => row.name.substring(0,40), - sortable: true - }, - { - name: "Apellido", - selector: row => row.lastName.substring(0,40), - sortable: true - }, - { - name: "Estatus", - selector: row => row.status?.substring(0,40) ?? "", - sortable: true - } - ]; - - const refreshListTown = (stateId: number, name: string) => { - setIsLoading(true); - const getTownsList = async () => { - try { - getTownsByState(stateId, name); - } catch (error: any) { - if (axios.isAxiosError(error)) { - error as AxiosError; - showErrorAxios(error); - } - } - } - getTownsList(); - setIsLoading(false); - }; - - const refreshListAdmins = (idTown: number) => { - setIsLoading(true); - const getAdminsList = async () => { - try { - getAdminListByTown(idTown); - } catch (error: any) { - if (axios.isAxiosError(error)) { - error as AxiosError; - showErrorAxios(error); - } - } - } - getAdminsList(); - setIsLoading(false); - }; - - if(isLoading) return - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx b/web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx deleted file mode 100644 index 5eb361a5..00000000 --- a/web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import { Dispatch, SetStateAction } from "react"; -import './assets/css/styles.css' -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faWindowClose, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; -import { useAdmin } from "../../../hooks/useAdmin"; -import { usePasswoordVisibility } from "../../../hooks/usePasswordVisibility"; -import { State } from "../../../infraestructure/entities/state"; -import { useTown } from "../../../hooks/useTown"; - -interface props { - handleClickToClose: () => void; - forceRenderList: () => void; - statesList : State[]; -} - -export const SuperadminPanelAdminRegister = ({handleClickToClose, forceRenderList, statesList}:props) => { - const { - register, - errors, - handleSubmit, - onSubmit, - } = useAdmin(forceRenderList, handleClickToClose); - - const { - values, - handleClickShowPassword, - handleMouseDownPassword - } = usePasswoordVisibility(); - - const {townsList, getTownsByState} = useTown(); - - return ( -- Estado - - - Pueblo mágico - - ----- } - columns={columns} data={adminList} selectableRows className="data_table" - /> - -- ); -} \ No newline at end of file diff --git a/web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx b/web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx deleted file mode 100644 index efc62d5e..00000000 --- a/web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Dispatch, SetStateAction, useState } from 'react'; -import './assets/css/styles.css'; -import { SuperadminPanelAdminRegister } from '../sa_panel_admin_register/sa_panel_admin_register'; -import { State } from '../../../infraestructure/entities/state'; -import { SuperAdminPanelAdminList } from '../sa_panel_admin_list/sa_panel_admin_list'; - -interface props { - isWindowActive: boolean; - setIsWindowActive: Dispatch- Registra el administrador --handleClickToClose()}/> - - -->; - statesList: State[]; -} - -export const SuperadminPanelAdminScreen = ({isWindowActive, setIsWindowActive, statesList}:props) => { - const [showRegisterPanel, setShowRegisterPanel] = useState(false); - const [renderCount, setRenderCount] = useState(0); - - const handleClickToClose = () => { - setIsWindowActive(false); - setShowRegisterPanel(false); - } - - const forceRenderList = () =>{ - setRenderCount(prevCount => prevCount + 1); - } - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx b/web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx deleted file mode 100644 index 9d74d986..00000000 --- a/web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import DataTable, { TableColumn } from 'react-data-table-component'; -import './assets/css/styles.css'; -import { LoadingSpinner } from '../../loading_spinner/loading_spinner'; -import { useCategory } from '../../../hooks/useCategory'; -import { Category } from '../../../infraestructure/entities/category'; -import { faTrash } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dispatch, SetStateAction, useEffect, useState } from 'react'; -import { ConfirmationDialog } from '../../confirmation_dialog_box/confirmation_dialog'; -import { toast } from 'react-toastify'; - -interface props { - isWindowActive: boolean; - setIsWindowActive: Dispatch- Administrar administradores - --- {showRegisterPanel - && --- } - - >; -} - -export const SuperAdminPanelCategoryList = ({isWindowActive, setIsWindowActive}:props) => { - const { - categoriesList, - pending, - deleteCategory, - } = useCategory(); - const [isDialogOpen, setIsDialogOpen] = useState(false); - const [dialogMessage, setDialogMessage] = useState(''); - const [categoryDeleted, setCategoryDeleted] = useState (null); - const [deleteCategoryBool, setDeleteCategoryBool] = useState(false); - - const deleteSelectedCategory = (category: Category) => { - toast.promise( - deleteCategory(category),{ - pending: "Eliminando categoría...", - success: "La categoría se ha eliminado correctamente", - error: "No se pudo eliminar la categoría" - } - ) - } - - useEffect(() => { - if(deleteCategoryBool && categoryDeleted){ - deleteSelectedCategory(categoryDeleted); - setDeleteCategoryBool(false); - } - }, [deleteCategoryBool]); - - const handleDeleteSelectedCategory = (category: Category) => { - setDialogMessage(`¿Desea eliminar la categoría ${category.nameES}?`) - setCategoryDeleted(category); - setIsDialogOpen(true); - setIsWindowActive(true); - } - - const handleToClose = () => { - setIsWindowActive(false); - setIsDialogOpen(false) - } - - const columns : TableColumn [] = [ - { - name: "Identificador", - selector: row => row.idCategory || 0, - sortable: true - }, - { - name: "Nombre en español", - selector: row => row.nameES, - sortable: true - }, - { - name: "Nombre en Inglés", - selector: row => row.nameEN, - sortable: true - }, - { - name: "Acciones", - cell: (row) => { - return ( - { - if(!isWindowActive){ - handleDeleteSelectedCategory(row); - } - }} - /> - ); - } - } - ]; - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx b/web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx deleted file mode 100644 index 675d0d68..00000000 --- a/web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { faWindowClose } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Dispatch, SetStateAction} from "react"; -import "./assets/css/styles.css"; -import { useCategory } from "../../../hooks/useCategory"; - -interface props { - handleClickToClose: () => void; - forceRenderList: () => void; -} - -export const SuperAdminPanelCategoryRegister = ({handleClickToClose, forceRenderList}: props) => { - const { - register, - handleSubmit, - errors, - onSubmit, - } = useCategory(forceRenderList, handleClickToClose); - - return ( -- } - disabled={isWindowActive} - columns={columns} data={categoriesList} className="data_table"/> - { - isDialogOpen && - } - -- ); -} \ No newline at end of file diff --git a/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx b/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx deleted file mode 100644 index 5717fed5..00000000 --- a/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import { faWindowClose, faLanguage } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import './css/styles.css' -import { ImageDropzone } from "../../image_dropzone/image_dropzone"; -import { Dispatch, SetStateAction, useEffect, useState } from "react"; -import { useTown } from "../../../hooks/useTown"; -import { State } from "../../../infraestructure/entities/state"; -import { Town } from "../../../infraestructure/entities/town"; - -interface props { - setWindowActive: Dispatch- Registra la categoría --handleClickToClose()}/> - - -->, - setActualWindowActive: Dispatch >, - statesList: State[] | null; - forceRenderList: () => void; - isRegister: boolean; - form?: Town; -} - -export const SuperadminPanelTownRegister = ({setWindowActive, statesList, forceRenderList, isRegister, form, - setActualWindowActive -}:props) => { - const [isEnglish, setIsEnglish] = useState(false); - const [spanishDescription, setSpanishDescription] = useState(""); - const [englishDescription, setEnglishDescription] = useState(""); - const [preview, setPreview] = useState (null); - const [image, setImage] = useState (null); - const [actualWindowVisibility, setActualWindowVisibility] = useState(true); - - const closeActualWindow = () => { - setWindowActive(false); - setActualWindowActive(false); - } - - const { - register, - setValue, - errors, - handleSubmit, - onSubmitRegister, - onSubmitUpdate, - } = useTown(forceRenderList, closeActualWindow); - - useEffect(()=> { - if(!isRegister && form){ - const setData = async () => { - setValue('idTown', form.idTown); - setValue('name',form.name); - setSpanishDescription(form?.descriptionES || ''); - setValue('descriptionES',form.descriptionES); - setEnglishDescription(form?.descriptionEN || ''); - setValue('descriptionEN',form.descriptionEN); - setValue('idState',form.idState); - setPreview(form.imageURL as string); - - const response = await fetch(form.imageURL as string); - const blob = await response.blob(); - const file = new File([blob],'image.jpg',{type: blob.type}); - setValue('imageURL', file); - } - setData(); - } - },[]) - - useEffect(() => { - if(image){ - setValue('imageURL', image, {shouldValidate: true}); - } - },[image]); - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx b/web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx deleted file mode 100644 index 4deeb58a..00000000 --- a/web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Dispatch, SetStateAction, useState } from 'react'; -import { SuperadminPanelTownRegister } from '../sa_panel_town_register/sa_panel_town_register'; -import './css/styles.css' -import { State } from '../../../infraestructure/entities/state'; -import { SuperadminPanelTownList } from '../sa_panel_town_list/sa_panel_town_list'; - -interface props { - windowActive: boolean; - setWindowActive: Dispatch- {isRegister ? "Registra el pueblo mágico": "Actualiza tu pueblo mágico"} --closeActualWindow()}/> - - -->; - statesList: State[]; -} - -export const SuperadminPanelTownScreen = ({windowActive,setWindowActive, statesList}:props) => { - const [showRegisterPanel, setShowRegisterPanel] = useState(false); - const [renderCount, setRenderCount] = useState(0); - - const forceRenderList = () =>{ - setRenderCount(prevCount => prevCount + 1); - } - - return ( - -- ); -} \ No newline at end of file diff --git a/web/src/components/sidebar_header/sidebar_header.tsx b/web/src/components/sidebar_header/sidebar_header.tsx deleted file mode 100644 index f23c496b..00000000 --- a/web/src/components/sidebar_header/sidebar_header.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { UserRole } from '../../constants/roles'; -import { useAuth } from '../../context/auth_context'; -import './assets/css/styles.css'; - -export const SidebarHeader = () => { - const {user} = useAuth(); - if(!user){ - return null; - } - - return ( -- Administrar pueblos mágicos - ----- - {showRegisterPanel - && - } - -- ); -} \ No newline at end of file diff --git a/web/src/constants/images_nuber.ts b/web/src/constants/images_nuber.ts deleted file mode 100644 index d9b2beb7..00000000 --- a/web/src/constants/images_nuber.ts +++ /dev/null @@ -1 +0,0 @@ -export const MIN_NUMBER_PLACE_IMAGES = 1; \ No newline at end of file diff --git a/web/src/constants/languages.ts b/web/src/constants/languages.ts deleted file mode 100644 index 770db8d7..00000000 --- a/web/src/constants/languages.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const languaguesList: string[] = [ - 'Español', - 'Inglés', -] \ No newline at end of file diff --git a/web/src/constants/roles.ts b/web/src/constants/roles.ts deleted file mode 100644 index dd45c329..00000000 --- a/web/src/constants/roles.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum UserRole { - ADMIN = "admin", - SUPERADMIN = "superadmin", -} - -export const SUPERADMIN_ROLE = UserRole.SUPERADMIN; -export const ADMIN_ROLE = UserRole.ADMIN; \ No newline at end of file diff --git a/web/src/constants/selected_panel.ts b/web/src/constants/selected_panel.ts deleted file mode 100644 index 0c2ef85c..00000000 --- a/web/src/constants/selected_panel.ts +++ /dev/null @@ -1,11 +0,0 @@ -export enum AdminSelectedPanel { - TOWN_INFO = "town_info", - PLACES = "places", - POINT_OF_INTEREST = "point_of_interest" -} - -export enum SuperAdminSelectedPanel { - TOWNS = "towns", - ADMINS = "admins", - CATEGORIES = "categories" -} \ No newline at end of file diff --git a/web/src/context/auth_context.tsx b/web/src/context/auth_context.tsx deleted file mode 100644 index 0a777141..00000000 --- a/web/src/context/auth_context.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { UserEntity } from "../infraestructure/entities/user"; -import axios from "axios"; -import { UserRole } from "../constants/roles"; -import { ReactNode, createContext, useContext, useEffect, useState } from "react"; - -type AuthContextType = { - user: UserEntity | null; - login: (user: UserEntity, token: string) => void; - logout: () => void; -}; - -const AuthContext = createContext--{user.role==UserRole.SUPERADMIN ? 'Superadmin': 'Admin'} Panel
-({ - user: null, - login: () => {}, - logout: () => {} -}); - -type AuthContextProviderProps = { - children: ReactNode; -} - -export const AuthContextProvider = ({children} : AuthContextProviderProps) => { - const [user, setUser] = useState (null); - const saveSession = async (user: UserEntity, token: string) => { - setUser(user); - localStorage.setItem("token",token); - localStorage.setItem("user",JSON.stringify(user)); - axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; - } - - const deleteSession = async () => { - setUser(null); - localStorage.removeItem("token"); - localStorage.removeItem("user"); - axios.defaults.headers.common["Authorization"] = ""; - } - - const login = async (user: UserEntity, token: string) => { - await saveSession(user, token); - } - - const logout = async () => { - await deleteSession(); - } - - const checkSession = async () => { - const token = localStorage.getItem("token"); - const user = localStorage.getItem("user"); - if(token && user){ - const sessionUser = JSON.parse(user); - await saveSession({email: sessionUser.email as string, name: sessionUser.name as string, role: sessionUser.role as UserRole}, token); - } - } - - useEffect(() => { - checkSession(); - }, []); - - const value = {user, login, logout}; - return {children} -}; - -export const useAuth = () => { - if(AuthContext == undefined){ - throw new Error("useAuth debe se usado dentro de un AuthContextProvider"); - } - return useContext(AuthContext); -}; \ No newline at end of file diff --git a/web/src/constants/api_routes.ts b/web/src/core/constants/api_routes.ts similarity index 53% rename from web/src/constants/api_routes.ts rename to web/src/core/constants/api_routes.ts index cdb28e94..1c403b23 100644 --- a/web/src/constants/api_routes.ts +++ b/web/src/core/constants/api_routes.ts @@ -1,13 +1,52 @@ +/** + * API route for admin operations. + */ export const API_ROUTE_ADMIN = "/admin"; + +/** + * API route for admin signup. + */ export const API_ROUTE_ADMIN_SIGNUP = API_ROUTE_ADMIN + "/signup"; + +/** + * API route for admin signin. + */ export const API_ROUTE_ADMIN_SIGNIN = API_ROUTE_ADMIN + "/signin"; + +/** + * API route for changing admin password. + */ export const API_ROUTE_ADMIN_CHANGE_PASSWORD = API_ROUTE_ADMIN + "/change-password"; + +/** + * API route for resetting admin password. + */ export const API_ROUTE_ADMIN_RESET_PASSWORD = API_ROUTE_ADMIN + "/reset-password"; + +/** + * API route for generating admin reset code. + */ export const API_ROUTE_ADMIN_GENERATE_RESET_CODE = API_ROUTE_ADMIN + "/get-reset-code"; + +/** + * API route for getting admin information. + */ export const API_ROUTE_ADMIN_WHOAMI = API_ROUTE_ADMIN + "/whoami"; -const API_ROUTE_STATE = "/state"; + +/** + * API route for state operations. + */ +export const API_ROUTE_STATE = "/state"; + +/** + * API route for point operations. + */ export const API_ROUTE_POINT = "/point"; + +/** + * API route for place operations. + */ export const API_ROUTE_PLACE = "/place"; diff --git a/web/src/constants/api_url.ts b/web/src/core/constants/api_url.ts similarity index 62% rename from web/src/constants/api_url.ts rename to web/src/core/constants/api_url.ts index b712d339..463d2127 100644 --- a/web/src/constants/api_url.ts +++ b/web/src/core/constants/api_url.ts @@ -1 +1,4 @@ +/** + * Base URL for the API. + */ export const APIUrl: String = "http://localhost:3005"; \ No newline at end of file diff --git a/web/src/core/constants/images_nuber.ts b/web/src/core/constants/images_nuber.ts new file mode 100644 index 00000000..e0472767 --- /dev/null +++ b/web/src/core/constants/images_nuber.ts @@ -0,0 +1,4 @@ +/** + * Minimum number of images required for a place. + */ +export const MIN_NUMBER_PLACE_IMAGES = 1; \ No newline at end of file diff --git a/web/src/core/constants/languages.ts b/web/src/core/constants/languages.ts new file mode 100644 index 00000000..9832daad --- /dev/null +++ b/web/src/core/constants/languages.ts @@ -0,0 +1,7 @@ +/** + * List of supported languages. + */ +export const languaguesList: string[] = [ + 'Español', // Spanish + 'Inglés', // English +] \ No newline at end of file diff --git a/web/src/core/constants/roles.ts b/web/src/core/constants/roles.ts new file mode 100644 index 00000000..fcc8e974 --- /dev/null +++ b/web/src/core/constants/roles.ts @@ -0,0 +1,17 @@ +/** + * Enum representing the different user roles. + */ +export enum UserRole { + ADMIN = "admin", // Admin role + SUPERADMIN = "superadmin", // Super admin role +} + +/** + * Constant representing the super admin role. + */ +export const SUPERADMIN_ROLE = UserRole.SUPERADMIN; + +/** + * Constant representing the admin role. + */ +export const ADMIN_ROLE = UserRole.ADMIN; \ No newline at end of file diff --git a/web/src/core/constants/selected_panel.ts b/web/src/core/constants/selected_panel.ts new file mode 100644 index 00000000..d9691ddb --- /dev/null +++ b/web/src/core/constants/selected_panel.ts @@ -0,0 +1,17 @@ +/** + * Enum representing the different panels available for an admin user. + */ +export enum AdminSelectedPanel { + TOWN_INFO = "town_info", // Panel for town information + PLACES = "places", // Panel for places + POINT_OF_INTEREST = "point_of_interest" // Panel for points of interest +} + +/** + * Enum representing the different panels available for a super admin user. + */ +export enum SuperAdminSelectedPanel { + TOWNS = "towns", // Panel for towns + ADMINS = "admins", // Panel for admins + CATEGORIES = "categories" // Panel for categories +} \ No newline at end of file diff --git a/web/src/core/context/auth_context.tsx b/web/src/core/context/auth_context.tsx new file mode 100644 index 00000000..51a2373b --- /dev/null +++ b/web/src/core/context/auth_context.tsx @@ -0,0 +1,92 @@ +import { UserEntity } from "../../data/datasource/api/entities/user"; +import axios from "axios"; +import { UserRole } from "../constants/roles"; +import { + ReactNode, + createContext, + useContext, + useEffect, + useState, +} from "react"; + +// Define the shape of the context state and actions +type AuthContextType = { + user: UserEntity | null; // The authenticated user or null if not authenticated + login: (user: UserEntity, token: string) => void; // Function to log in the user + logout: () => void; // Function to log out the user +}; + +// Create the context with default values +const AuthContext = createContext({ + user: null, + login: () => {}, + logout: () => {}, +}); + +// Define the props for the AuthContextProvider component +type AuthContextProviderProps = { + children: ReactNode; // The child components that will have access to the context +}; + +// Create the provider component +export const AuthContextProvider = ({ children }: AuthContextProviderProps) => { + const [user, setUser] = useState (null); // State to track the authenticated user + + // Function to save the session data in local storage and set the authorization header + const saveSession = async (user: UserEntity, token: string) => { + setUser(user); + localStorage.setItem("token", token); + localStorage.setItem("user", JSON.stringify(user)); + axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; + }; + + // Function to delete the session data from local storage and clear the authorization header + const deleteSession = async () => { + setUser(null); + localStorage.removeItem("token"); + localStorage.removeItem("user"); + axios.defaults.headers.common["Authorization"] = ""; + }; + + // Function to log in the user by saving the session + const login = async (user: UserEntity, token: string) => { + await saveSession(user, token); + }; + + // Function to log out the user by deleting the session + const logout = async () => { + await deleteSession(); + }; + + // Check if there is an existing session in local storage when the component mounts + useEffect(() => { + const checkSession = async () => { + const token = localStorage.getItem("token"); + const user = localStorage.getItem("user"); + if (token && user) { + const sessionUser = JSON.parse(user); + await saveSession( + { + email: sessionUser.email as string, + name: sessionUser.name as string, + role: sessionUser.role as UserRole, + }, + token + ); + } + }; + checkSession(); + }, []); + + // Provide the context value to child components + const value = { user, login, logout }; + return {children} ; +}; + +// Custom hook to use the AuthContext +export const useAuth = () => { + if (AuthContext === undefined) { + throw new Error("useAuth debe se usado dentro de un AuthContextProvider"); + } + return useContext(AuthContext); +}; diff --git a/web/src/context/message_context.tsx b/web/src/core/context/message_context.tsx similarity index 50% rename from web/src/context/message_context.tsx rename to web/src/core/context/message_context.tsx index 1ce309be..4bee0a31 100644 --- a/web/src/context/message_context.tsx +++ b/web/src/core/context/message_context.tsx @@ -1,12 +1,14 @@ import { createContext, ReactNode, useContext, useState } from "react"; +// Define the shape of the context state and actions type MessageContextType = { - isVisible: boolean; - message: string; - showMessage: (message: string) => void; - hideMessage: () => void; + isVisible: boolean; // Indicates if the message is visible + message: string; // The message to be displayed + showMessage: (message: string) => void; // Function to show the message + hideMessage: () => void; // Function to hide the message } +// Create the context with default values const MessageContext = createContext({ isVisible: false, message: "", @@ -14,13 +16,17 @@ const MessageContext = createContext ({ hideMessage: () => {} }); +// Define the props for the MessageContextProvider component type MessageContextProviderProps = { - children: ReactNode; + children: ReactNode; // The child components that will have access to the context } +// Create the provider component export const MessageContextProvider = ({children}: MessageContextProviderProps) => { - const [isVisible, setIsVisible] = useState (false); - const [message, setMessage] = useState (""); + const [isVisible, setIsVisible] = useState (false); // State to track visibility of the message + const [message, setMessage] = useState (""); // State to track the message content + + // Function to show the message and hide it after 3 seconds const showMessage = (message: string) => { setIsVisible(true); setMessage(message); @@ -30,17 +36,20 @@ export const MessageContextProvider = ({children}: MessageContextProviderProps) }, 3000); }; + // Function to hide the message immediately const hideMessage = () => { setIsVisible(false); setMessage(""); }; + // Provide the context value to child components const value = {isVisible, message, showMessage, hideMessage}; return {children} } +// Custom hook to use the MessageContext export const useMessage = () => { - if(MessageContext == undefined){ + if(MessageContext === undefined){ throw new Error("useMessage debe se usado dentro de un MessageContextProvider"); } return useContext(MessageContext); diff --git a/web/src/core/errors/CustomError.ts b/web/src/core/errors/CustomError.ts new file mode 100644 index 00000000..a8eeb8e7 --- /dev/null +++ b/web/src/core/errors/CustomError.ts @@ -0,0 +1,26 @@ +/** + * CustomErrorContent defines the structure of the error content. + */ +export type CustomErrorContent = { + message: string; + context?: { [key: string]: any }; +}; + +/** + * CustomError is an abstract base class for custom errors. + * It extends the built-in Error class and adds additional properties. + */ +export abstract class CustomError extends Error { + // Abstract properties that must be implemented by subclasses + abstract readonly statusCode: number; + abstract readonly logging: boolean; + + /** + * Constructs a new CustomError instance. + * @param message - The error message. + */ + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, CustomError.prototype); + } +} diff --git a/web/src/core/errors/UnautherizedError.ts b/web/src/core/errors/UnautherizedError.ts new file mode 100644 index 00000000..e0316e82 --- /dev/null +++ b/web/src/core/errors/UnautherizedError.ts @@ -0,0 +1,56 @@ +import { CustomError } from "./CustomError"; + +/** + * UnauthorizedError is a custom error class that extends CustomError. + * It represents an error when a user is not authorized to perform an action. + */ +export default class UnauthorizedError extends CustomError { + // HTTP status code for unauthorized error + private static readonly _statusCode = 401; + private readonly _code: number; + private readonly _logging: boolean; + private readonly _context: { [key: string]: any }; + + /** + * Constructs a new UnauthorizedError instance. + * @param params - Optional parameters for the error. + * @param params.code - Custom error code (default is 401). + * @param params.message - Custom error message (default is "You are not authorized"). + * @param params.logging - Flag to indicate if the error should be logged (default is false). + * @param params.context - Additional context for the error. + */ + constructor(params?: { code?: number; message?: string; logging?: boolean; context?: { [key: string]: any } }) { + const { code, message, logging } = params || {}; + + super(message || "You are not authorized"); + this._code = code || UnauthorizedError._statusCode; + this._logging = logging || false; + this._context = params?.context || {}; + + Object.setPrototypeOf(this, UnauthorizedError.prototype); + } + + /** + * Returns an array of error details. + * @returns An array containing the error message and context. + */ + get errors() { + return [{ message: this.message, context: this._context }]; + } + + /** + * Returns the HTTP status code for the error. + * @returns The status code. + */ + get statusCode() { + return this._code; + } + + /** + * Indicates if the error should be logged. + * @returns True if the error should be logged, otherwise false. + */ + get logging() { + return this._logging; + } +} diff --git a/web/src/core/router/login_route.tsx b/web/src/core/router/login_route.tsx new file mode 100644 index 00000000..d75a3988 --- /dev/null +++ b/web/src/core/router/login_route.tsx @@ -0,0 +1,15 @@ +import { Navigate, Outlet } from "react-router-dom"; +import { useAuth } from "../context/auth_context"; + +// Component to handle login route +export const LoginRoute = () => { + const { user } = useAuth(); + + // If user is authenticated, redirect to home page + if (user) { + return; + } + + // Render the login page if user is not authenticated + return ; +}; diff --git a/web/src/core/router/protected_route.tsx b/web/src/core/router/protected_route.tsx new file mode 100644 index 00000000..8bb5c233 --- /dev/null +++ b/web/src/core/router/protected_route.tsx @@ -0,0 +1,26 @@ +import { Navigate } from "react-router-dom"; +import { useAuth } from "../context/auth_context"; +import { UserRole } from "../constants/roles"; +import { AdminHomePage } from "../../presentation/admin/panel/admin_home_page"; +import { SuperAdminHomePage } from "../../presentation/superadmin/panel/super_admin_home_page"; + +// Component to handle protected routes based on user role +export const ProtectedRoute = () => { + const { user, logout } = useAuth(); + + // If no user is authenticated, redirect to login page + if (!user) { + return ; + } else { + // Redirect based on user role + if (user.role === UserRole.ADMIN) { + return ; + } else if (user.role === UserRole.SUPERADMIN) { + return ; + } else { + // Logout and redirect to login if user role is not recognized + logout(); + return ; + } + } +}; diff --git a/web/src/core/router/router.tsx b/web/src/core/router/router.tsx new file mode 100644 index 00000000..50a1eec7 --- /dev/null +++ b/web/src/core/router/router.tsx @@ -0,0 +1,30 @@ +import { createBrowserRouter } from "react-router-dom"; +import { ProtectedRoute } from "./protected_route"; +import { LoginPage } from "../../presentation/login/login_page"; + +// Create the router configuration +export const router = createBrowserRouter([ + { + // Protected routes that require authentication + element: , + children: [ + { + // Default route for authenticated users + index: true, + path: "/", + element: + } + ] + }, + { + // Public route for login page + element: , + children: [ + { + // Route for login page + path: "/login", + element: + } + ] + } +]); \ No newline at end of file diff --git a/web/src/core/utils/Messages.ts b/web/src/core/utils/Messages.ts new file mode 100644 index 00000000..5418bbc4 --- /dev/null +++ b/web/src/core/utils/Messages.ts @@ -0,0 +1,36 @@ +import axios, { AxiosError } from "axios"; +import { toast } from "react-toastify"; + +/** + * Displays an error message using react-toastify based on the type of Axios error. + * + * @param {AxiosError} error - The error object returned by Axios. + */ +export const showErrorAxios = (error: AxiosError) => { + let message = ""; + + // Determine the error message based on the error code + switch(error.code){ + case(axios.AxiosError.ERR_BAD_REQUEST): + message = "Acceso no autorizado"; // Unauthorized access + break; + case(axios.AxiosError.ERR_NETWORK): + message = "Conexión con el servidor fallida"; // Server connection failed + break; + default: + message = error.message; // Default to the error message provided by Axios + break; + } + + // Display the error message using react-toastify + toast.error(message, { + position: "bottom-right", // Position the toast at the bottom-right corner + autoClose: 1500, // Automatically close the toast after 1.5 seconds + hideProgressBar: false, // Show the progress bar + closeOnClick: true, // Close the toast when clicked + pauseOnHover: false, // Do not pause the toast on hover + draggable: true, // Allow the toast to be draggable + progress: undefined, // Use the default progress bar behavior + theme: "colored" // Use the colored theme for the toast + }); +} \ No newline at end of file diff --git a/web/src/data/datasource/admin_datasource.ts b/web/src/data/datasource/admin_datasource.ts new file mode 100644 index 00000000..0bf0b76c --- /dev/null +++ b/web/src/data/datasource/admin_datasource.ts @@ -0,0 +1,55 @@ +import { Admin, AdminFormValues } from "./api/entities/admin_form_values"; +import { ResetPasswordValues } from "./api/entities/reset_password_values"; + +/** + * Interface representing a data source for handling admin-related operations. + */ +export interface AdminDatasourceInf { + /** + * Registers a new admin. + * @param form - The admin data to register. + * @returns A promise that resolves when the registration is complete. + */ + registerAdmin(form: AdminFormValues): Promise ; + + /** + * Retrieves admin information based on a token. + * @param token - The authentication token. + * @returns A promise that resolves to an Admin object. + */ + getAdminInfo(token: string): Promise ; + + /** + * Changes the password for an admin. + * @param token - The authentication token. + * @param prevPassword - The previous password. + * @param newPassword - The new password. + * @returns A promise that resolves when the password change is complete. + */ + changePassword( + token: string, + prevPassword: string, + newPassword: string + ): Promise ; + + /** + * Retrieves a list of admins by town. + * @param idTown - The ID of the town. + * @returns A promise that resolves to an array of Admin objects. + */ + getAdminsByTown(idTown: number): Promise ; + + /** + * Generates a reset code for the given email. + * @param email - The email address to send the reset code to. + * @returns A promise that resolves when the reset code is generated. + */ + generateResetCode(email: string): Promise ; + + /** + * Resets the password using the provided reset form values. + * @param form - The reset password form values. + * @returns A promise that resolves when the password reset is complete. + */ + resetPassword(form: ResetPasswordValues): Promise ; +} diff --git a/web/src/data/datasources/prod/admin_datasource.ts b/web/src/data/datasource/api/admin_datasource.ts similarity index 58% rename from web/src/data/datasources/prod/admin_datasource.ts rename to web/src/data/datasource/api/admin_datasource.ts index a89fa78c..2e4ac80d 100644 --- a/web/src/data/datasources/prod/admin_datasource.ts +++ b/web/src/data/datasource/api/admin_datasource.ts @@ -1,12 +1,9 @@ import axios from "axios"; -import { AdminDatasourceInf } from "../../../infraestructure/datasources/admin_datasource"; -import { - Admin, - AdminFormValues, -} from "../../../infraestructure/entities/admin_form_values"; -import { APIUrl } from "../../../constants/api_url"; -import { AdminModel } from "../../models/prod/AdminModel"; -import { UserRole } from "../../../constants/roles"; +import { AdminDatasourceInf } from "../admin_datasource"; +import { Admin, AdminFormValues } from "./entities/admin_form_values"; +import { APIUrl } from "../../../core/constants/api_url"; +import { AdminModel } from "../../../domain/model/AdminModel"; +import { UserRole } from "../../../core/constants/roles"; import { API_ROUTE_ADMIN, API_ROUTE_ADMIN_CHANGE_PASSWORD, @@ -14,10 +11,15 @@ import { API_ROUTE_ADMIN_RESET_PASSWORD, API_ROUTE_ADMIN_SIGNUP, API_ROUTE_ADMIN_WHOAMI, -} from "../../../constants/api_routes"; -import { ResetPasswordValues } from "../../../infraestructure/entities/reset_password_values"; +} from "../../../core/constants/api_routes"; +import { ResetPasswordValues } from "./entities/reset_password_values"; export class AdminDatasourceProd implements AdminDatasourceInf { + /** + * Registers a new admin using the provided form data. + * @param form - The admin data to be registered. + * @returns A promise that resolves when the admin is successfully registered. + */ async registerAdmin(form: AdminFormValues): Promise { await axios.post(APIUrl + API_ROUTE_ADMIN_SIGNUP, { email: form.email, @@ -28,6 +30,11 @@ export class AdminDatasourceProd implements AdminDatasourceInf { }); } + /** + * Retrieves admin information using the provided token. + * @param token - The token of the admin. + * @returns A promise that resolves to an Admin object. + */ async getAdminInfo(token: string): Promise { const { data } = await axios.get ( APIUrl + API_ROUTE_ADMIN_WHOAMI, @@ -50,6 +57,13 @@ export class AdminDatasourceProd implements AdminDatasourceInf { return admin; } + /** + * Changes the password of the admin. + * @param token - The token of the admin. + * @param prevPassword - The previous password. + * @param newPassword - The new password. + * @returns A promise that resolves when the password is successfully changed. + */ async changePassword( token: string, prevPassword: string, @@ -69,6 +83,11 @@ export class AdminDatasourceProd implements AdminDatasourceInf { ); } + /** + * Retrieves a list of admins by town ID. + * @param idTown - The ID of the town. + * @returns A promise that resolves to an array of Admin objects. + */ async getAdminsByTown(idTown: number): Promise { const { data } = await axios.get ( APIUrl + API_ROUTE_ADMIN + `/${idTown}` @@ -85,12 +104,22 @@ export class AdminDatasourceProd implements AdminDatasourceInf { return admins; } + /** + * Generates a reset code for the given email. + * @param email - The email of the admin. + * @returns A promise that resolves when the reset code is successfully generated. + */ async generateResetCode(email: string): Promise { await axios.post(APIUrl + API_ROUTE_ADMIN_GENERATE_RESET_CODE, { email: email, }); } + /** + * Resets the password using the provided form data. + * @param form - The reset password form values. + * @returns A promise that resolves when the password is successfully reset. + */ async resetPassword(form: ResetPasswordValues): Promise { await axios.post(APIUrl + API_ROUTE_ADMIN_RESET_PASSWORD, { email: form.email, diff --git a/web/src/data/datasource/api/category_datasource.ts b/web/src/data/datasource/api/category_datasource.ts new file mode 100644 index 00000000..e364270d --- /dev/null +++ b/web/src/data/datasource/api/category_datasource.ts @@ -0,0 +1,62 @@ +import axios from "axios"; +import { CategoryDatasourceInf } from "../category_datasource"; +import { Category, CategoryFormValues } from "./entities/category"; +import { APIUrl } from "../../../core/constants/api_url"; +import { CategoryModel } from "../../../domain/model/CategoryModel"; + +export class CategoryDatasourceProd implements CategoryDatasourceInf { + /** + * Registers a new category using the provided form data. + * @param form - The category data to be registered. + * @returns A promise that resolves when the category is successfully registered. + */ + async registerCategory(form: CategoryFormValues): Promise { + await axios.post(APIUrl + "/category", { + nameES: form.nameES, + nameEN: form.nameEN, + }); + } + + /** + * Retrieves a list of categories. + * @returns A promise that resolves to an array of Category objects. + */ + async getCategories(): Promise { + const { data: dataES } = await axios.get ( + APIUrl + "/category/", + { + params: { + lang: "ES", + }, + } + ); + const { data: dataEN } = await axios.get ( + APIUrl + "/category/", + { + params: { + lang: "EN", + }, + } + ); + const categories: Category[] = []; + for (let i = 0; i < dataES.length; i++) { + const category: Category = { + idCategory: dataES[i].idCategory, + nameES: dataES[i].name, + nameEN: dataEN[i].name, + }; + categories.push(category); + } + + return categories; + } + + /** + * Deletes a category by its ID. + * @param category - The category to be deleted. + * @returns A promise that resolves when the category is successfully deleted. + */ + async deleteCategory(category: Category): Promise { + await axios.delete(APIUrl + `/category/${category.idCategory}`); + } +} diff --git a/web/src/infraestructure/entities/admin_form_values.ts b/web/src/data/datasource/api/entities/admin_form_values.ts similarity index 61% rename from web/src/infraestructure/entities/admin_form_values.ts rename to web/src/data/datasource/api/entities/admin_form_values.ts index 69786190..f6c71772 100644 --- a/web/src/infraestructure/entities/admin_form_values.ts +++ b/web/src/data/datasource/api/entities/admin_form_values.ts @@ -1,5 +1,8 @@ -import { UserRole } from "../../constants/roles"; +import { UserRole } from "../../../../core/constants/roles"; +/** + * Interface representing the values of an admin form. + */ export interface AdminFormValues { email: string; name: string; @@ -9,6 +12,9 @@ export interface AdminFormValues { townAdmin: number; } +/** + * Interface representing an admin. + */ export interface Admin { email: string; name: string; @@ -18,8 +24,11 @@ export interface Admin { status?: string; } +/** + * Interface representing the values required to change an admin's password. + */ export interface AdminPasswordValues { prevPassword: string; newPassword: string; newPasswordConfirm: string; -} \ No newline at end of file +} diff --git a/web/src/data/datasource/api/entities/category.ts b/web/src/data/datasource/api/entities/category.ts new file mode 100644 index 00000000..3edd3dc1 --- /dev/null +++ b/web/src/data/datasource/api/entities/category.ts @@ -0,0 +1,16 @@ +/** + * Interface representing a category. + */ +export interface Category { + idCategory: number; + nameES: string; + nameEN: string; +} + +/** + * Interface representing the values of a category form. + */ +export interface CategoryFormValues { + nameES: string; + nameEN: string; +} \ No newline at end of file diff --git a/web/src/data/datasource/api/entities/image.ts b/web/src/data/datasource/api/entities/image.ts new file mode 100644 index 00000000..960b6ecf --- /dev/null +++ b/web/src/data/datasource/api/entities/image.ts @@ -0,0 +1,7 @@ +/** + * Interface representing an image. + */ +export interface Image { + file: File; + preview: string; +} \ No newline at end of file diff --git a/web/src/data/datasource/api/entities/login_form_values.ts b/web/src/data/datasource/api/entities/login_form_values.ts new file mode 100644 index 00000000..f7c8007d --- /dev/null +++ b/web/src/data/datasource/api/entities/login_form_values.ts @@ -0,0 +1,7 @@ +/** + * Interface representing the values of a login form. + */ +export interface LoginFormValues { + email: string; + password: string; +} \ No newline at end of file diff --git a/web/src/infraestructure/entities/place.ts b/web/src/data/datasource/api/entities/place.ts similarity index 69% rename from web/src/infraestructure/entities/place.ts rename to web/src/data/datasource/api/entities/place.ts index ca43cd08..2abb1e14 100644 --- a/web/src/infraestructure/entities/place.ts +++ b/web/src/data/datasource/api/entities/place.ts @@ -1,6 +1,9 @@ -export interface Place{ +/** + * Interface representing a place. + */ +export interface Place { idTown: number; - idPlace? : number; + idPlace?: number; name: string; categoriesId: number[]; descriptions?: string[]; @@ -15,6 +18,9 @@ export interface Place{ address: string; } +/** + * Enum representing available days. + */ export enum AvailableDays { WEEKEND = 'weekend', ALL_DAYS = 'all_days', @@ -22,19 +28,28 @@ export enum AvailableDays { CUSTOM = 'custom' } -export interface availableDaysOption{ +/** + * Interface representing an available days option. + */ +export interface availableDaysOption { option: AvailableDays; name: string; } -export const availableDaysList= [ +/** + * List of available days options. + */ +export const availableDaysList = [ { option: AvailableDays.WEEKEND, name: 'Fines de semana' }, { option: AvailableDays.ALL_DAYS, name: 'Todos los dias' }, { option: AvailableDays.WEEKDAYS, name: 'Lunes a Viernes' }, { option: AvailableDays.CUSTOM, name: 'Personalizado' } ]; -export const EmptyPlace : Place = { +/** + * Constant representing an empty place. + */ +export const EmptyPlace: Place = { idTown: -1, idPlace: -1, name: "", @@ -46,4 +61,4 @@ export const EmptyPlace : Place = { closeAt: 0, available: AvailableDays.WEEKEND, address: '' -} \ No newline at end of file +}; \ No newline at end of file diff --git a/web/src/infraestructure/entities/poi.ts b/web/src/data/datasource/api/entities/poi.ts similarity index 76% rename from web/src/infraestructure/entities/poi.ts rename to web/src/data/datasource/api/entities/poi.ts index cdbfcb7e..ad5936a3 100644 --- a/web/src/infraestructure/entities/poi.ts +++ b/web/src/data/datasource/api/entities/poi.ts @@ -1,3 +1,6 @@ +/** + * Interface representing a point of interest. + */ export interface PointOfInterest { idPoint?: number; idPlace: number; @@ -9,6 +12,9 @@ export interface PointOfInterest { directionsES: string; } +/** + * Constant representing an empty point of interest. + */ export const EmptyPointOfInterest: PointOfInterest = { idPoint: 0, idPlace: 0, @@ -18,4 +24,4 @@ export const EmptyPointOfInterest: PointOfInterest = { contentES: '', directionsEN: '', directionsES: '' -} \ No newline at end of file +}; \ No newline at end of file diff --git a/web/src/infraestructure/entities/reset_password_values.ts b/web/src/data/datasource/api/entities/reset_password_values.ts similarity index 62% rename from web/src/infraestructure/entities/reset_password_values.ts rename to web/src/data/datasource/api/entities/reset_password_values.ts index a353e140..e7da0355 100644 --- a/web/src/infraestructure/entities/reset_password_values.ts +++ b/web/src/data/datasource/api/entities/reset_password_values.ts @@ -1,3 +1,6 @@ +/** + * Interface representing the values required to reset a password. + */ export interface ResetPasswordValues { email: string; code: number; diff --git a/web/src/data/datasource/api/entities/state.ts b/web/src/data/datasource/api/entities/state.ts new file mode 100644 index 00000000..2451f5fe --- /dev/null +++ b/web/src/data/datasource/api/entities/state.ts @@ -0,0 +1,8 @@ +/** + * Interface representing a state. + */ +export interface State { + stateId: number; + name: string; + imageURL: string; +} \ No newline at end of file diff --git a/web/src/data/datasource/api/entities/town.ts b/web/src/data/datasource/api/entities/town.ts new file mode 100644 index 00000000..c3b08f74 --- /dev/null +++ b/web/src/data/datasource/api/entities/town.ts @@ -0,0 +1,12 @@ +/** + * Interface representing a town. + */ +export interface Town { + idTown: number; + name: string; + descriptionES?: string; + descriptionEN?: string; + idState: number; + state: string; + imageURL?: string | File; +} \ No newline at end of file diff --git a/web/src/data/datasource/api/entities/user.ts b/web/src/data/datasource/api/entities/user.ts new file mode 100644 index 00000000..a824fa72 --- /dev/null +++ b/web/src/data/datasource/api/entities/user.ts @@ -0,0 +1,223 @@ +import { UserRole } from "../../../../core/constants/roles"; + +/** + * Interface representing a user entity. + */ +export interface UserEntity { + name: string; + lastName?: string; + email: string; + role: UserRole; +} + +/** + * Interface representing a logged-in user. + */ +export interface LoggedInUser { + user: UserEntity; + token: string; +} + +/** + * Interface representing user information. + */ +export interface UserInfo { + name?: string; + lastName?: string; + email: string; +} + +/** + * Class for converting JSON strings to UserEntity objects and vice versa. + */ +export class Convert { + public static toUser(json: string): UserEntity { + return cast(JSON.parse(json), r("User")); + } + + public static userToJson(value: UserEntity): string { + return JSON.stringify(uncast(value, r("User")), null, 2); + } +} + +function invalidValue(typ: any, val: any, key: any, parent: any = ""): never { + const prettyTyp = prettyTypeName(typ); + const parentText = parent ? ` on ${parent}` : ""; + const keyText = key ? ` for key "${key}"` : ""; + throw Error( + `Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify( + val + )}` + ); +} + +function prettyTypeName(typ: any): string { + if (Array.isArray(typ)) { + if (typ.length === 2 && typ[0] === undefined) { + return `an optional ${prettyTypeName(typ[1])}`; + } else { + return `one of [${typ + .map((a) => { + return prettyTypeName(a); + }) + .join(", ")}]`; + } + } else if (typeof typ === "object" && typ.literal !== undefined) { + return typ.literal; + } else { + return typeof typ; + } +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => (map[p.json] = { key: p.js, typ: p.typ })); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => (map[p.js] = { key: p.json, typ: p.typ })); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform( + val: any, + typ: any, + getProps: any, + key: any = "", + parent: any = "" +): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val, key, parent); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val, key, parent); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue( + cases.map((a) => { + return l(a); + }), + val, + key, + parent + ); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent); + return val.map((el) => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue(l("Date"), val, key, parent); + } + return d; + } + + function transformObject( + props: { [k: string]: any }, + additional: any, + val: any + ): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue(l(ref || "object"), val, key, parent); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach((key) => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) + ? val[key] + : undefined; + result[prop.key] = transform(v, prop.typ, getProps, key, ref); + }); + Object.getOwnPropertyNames(val).forEach((key) => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps, key, ref); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val, key, parent); + } + if (typ === false) return invalidValue(typ, val, key, parent); + let ref: any = undefined; + while (typeof typ === "object" && typ.ref !== undefined) { + ref = typ.ref; + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") + ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") + ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") + ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val, key, parent); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast (val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast (val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function l(typ: any) { + return { literal: typ }; +} + + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + User: o( + [ + { json: "email", js: "email", typ: "" }, + { json: "name", js: "name", typ: "" }, + { json: "role", js: "role", typ: "" }, + ], + false + ), +}; diff --git a/web/src/data/datasource/api/login_datasource.ts b/web/src/data/datasource/api/login_datasource.ts new file mode 100644 index 00000000..9040460b --- /dev/null +++ b/web/src/data/datasource/api/login_datasource.ts @@ -0,0 +1,41 @@ +import { LoginDatasource } from "../login_datasource"; +import { LoginFormValues } from "./entities/login_form_values"; +import axios from "axios"; +import { LoggedInUser } from "./entities/user"; +import { LoggedInUserModel } from "../../../domain/model/LoggedInUserModel"; +import { UserRole } from "../../../core/constants/roles"; +import { APIUrl } from "../../../core/constants/api_url"; + +/** + * Implementation of the LoginDatasource interface. + */ +export class LoginDatasourceImpl implements LoginDatasource { + /** + * Retrieves a token for the given login form values. + * @param form - The login form values. + * @returns A promise that resolves to a logged-in user. + */ + async getToken(form: LoginFormValues): Promise { + const { email, password } = form; + const { data } = await axios.post ( + APIUrl + "/admin/signin", + { + email: email, + password: password, + } + ); + const user: LoggedInUser = { + user: { + email: data.email, + name: data.name, + role: + data.role === UserRole.SUPERADMIN + ? UserRole.SUPERADMIN + : UserRole.ADMIN, + }, + token: data.token, + }; + + return user; + } +} diff --git a/web/src/data/datasource/api/place_datasource.ts b/web/src/data/datasource/api/place_datasource.ts new file mode 100644 index 00000000..88145c21 --- /dev/null +++ b/web/src/data/datasource/api/place_datasource.ts @@ -0,0 +1,128 @@ +import axios from "axios"; +import { APIUrl } from "../../../core/constants/api_url"; +import { PlaceDatasourceInf } from "../place_datasource"; +import { AvailableDays, Place } from "./entities/place"; +import { + PlaceModel, + placeModelToEntity, +} from "../../../domain/model/PlaceModel"; + +export class PlaceDatasourceProd implements PlaceDatasourceInf { + /** + * Registers a new place using the provided form data. + * @param form - The place data to be registered. + * @returns A promise that resolves when the place is successfully registered. + */ + async registerPlace(form: Place): Promise { + const formToSend = new FormData(); + formToSend.append("available", form.available); + formToSend.append("idTown", String(form.idTown)); + formToSend.append("name", form.name); + formToSend.append("categoriesId", form.categoriesId.join(",")); + formToSend.append("descriptionES", form.descriptions?.[0] ?? ""); + formToSend.append("descriptionEN", form.descriptions?.[1] ?? ""); + formToSend.append("image", form.imagesList?.[0] ?? ""); + formToSend.append("latitude", String(form.latitude)); + formToSend.append("longitude", String(form.longitude)); + formToSend.append("openAt", String(form.openAt)); + formToSend.append("closeAt", String(form.closeAt)); + formToSend.append("address", form.address); + + if (form.available === AvailableDays.CUSTOM) { + formToSend.append("startDate", String(form.startDate)); + formToSend.append("endDate", String(form.endDate)); + } + + const headers = { + "Content-Type": "multipart/form-data", + }; + + await axios.post(APIUrl + "/place", formToSend, { headers }); + } + + /** + * Retrieves a list of places by town ID. + * @param idTown - The ID of the town. + * @returns A promise that resolves to an array of Place objects. + */ + async getPlacesByTown(idTown: number): Promise { + const { data } = await axios.get ( + APIUrl + `/place/town/${idTown}/place`, + { + params: { + lang: "ES", + }, + } + ); + + const places = data.map((dataES) => { + return placeModelToEntity(dataES); + }); + + return places; + } + + /** + * Retrieves a place by its ID. + * @param idPlace - The ID of the place. + * @returns A promise that resolves to a Place object. + */ + async getPlaceById(idPlace: number): Promise { + const { data: dataES } = await axios.get ( + APIUrl + `/place/${idPlace}`, + { + params: { + lang: "ES", + }, + } + ); + + const { data: dataEN } = await axios.get ( + APIUrl + `/place/${idPlace}`, + { + params: { + lang: "EN", + }, + } + ); + + const place: Place = placeModelToEntity(dataES); + place.descriptions?.push(dataEN.description); + + return place; + } + + /** + * Updates an existing place using the provided form data. + * @param place - The place data to be updated. + * @returns A promise that resolves when the place is successfully updated. + */ + async updatePlace(place: Place): Promise { + const formToSend = new FormData(); + formToSend.append("available", place.available); + formToSend.append("idTown", String(place.idTown)); + formToSend.append("name", place.name); + formToSend.append("categoriesId", place.categoriesId.join(",")); + formToSend.append("descriptionES", place.descriptions?.[0] ?? ""); + formToSend.append("descriptionEN", place.descriptions?.[1] ?? ""); + formToSend.append("image", place.imagesList?.[0] ?? ""); + formToSend.append("latitude", String(place.latitude)); + formToSend.append("longitude", String(place.longitude)); + formToSend.append("openAt", String(place.openAt)); + formToSend.append("closeAt", String(place.closeAt)); + formToSend.append("address", place.address); + + if (place.available === AvailableDays.CUSTOM) { + formToSend.append("startDate", String(place.startDate)); + formToSend.append("endDate", String(place.endDate)); + } + + const headers = { + "Content-Type": "multipart/form-data", + }; + + await axios.patch(APIUrl + `/place/${place.idPlace}`, formToSend, { + headers, + }); + } +} diff --git a/web/src/data/datasource/api/poi_datasource.ts b/web/src/data/datasource/api/poi_datasource.ts new file mode 100644 index 00000000..206f5c92 --- /dev/null +++ b/web/src/data/datasource/api/poi_datasource.ts @@ -0,0 +1,106 @@ +import axios from "axios"; +import { Buffer } from "buffer"; +import { PoiDatasourceInf } from "../poi_datasource"; +import { PointOfInterest } from "./entities/poi"; +import { APIUrl } from "../../../core/constants/api_url"; +import { + API_ROUTE_PLACE, + API_ROUTE_POINT, +} from "../../../core/constants/api_routes"; +import { POIModel, POIModelToEntity } from "../../../domain/model/POIModel"; + +export class POIDatasourceProd implements PoiDatasourceInf { + /** + * Registers a new point of interest using the provided form data. + * @param form - The point of interest data to be registered. + * @returns A promise that resolves when the point is successfully registered. + */ + async registerPoint(form: PointOfInterest): Promise { + const formToSend = new FormData(); + formToSend.append("idPlace", String(form.idPlace)); + formToSend.append("name", form.name); + formToSend.append("image", form.image); + formToSend.append("contentEN", form.contentEN); + formToSend.append("contentES", form.contentES); + formToSend.append("directionsEN", form.directionsEN); + formToSend.append("directionsES", form.directionsES); + + const headers = { + "Content-Type": "multipart/form-data", + }; + + await axios.post(APIUrl + API_ROUTE_POINT, formToSend, { headers }); + } + + /** + * Retrieves a list of points of interest by place ID. + * @param idPlace - The ID of the place. + * @returns A promise that resolves to an array of PointOfInterest objects. + */ + async getPOIsByPlace(idPlace: number): Promise { + const { data: dataES } = await axios.get ( + APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT, + { + params: { + lang: "ES", + }, + } + ); + + const poiList = dataES.map((dataESModel) => { + return POIModelToEntity(dataESModel); + }); + + return poiList; + } + + /** + * Retrieves a point of interest by its ID. + * @param idPoint - The ID of the point of interest. + * @returns A promise that resolves to a PointOfInterest object. + */ + async getPOIById(idPoint: number): Promise { + const { data: dataES } = await axios.get ( + APIUrl + API_ROUTE_POINT + `/${idPoint}`, + { + params: { + lang: "ES", + }, + } + ); + + const { data: dataEN } = await axios.get ( + APIUrl + API_ROUTE_POINT + `/${idPoint}`, + { + params: { + lang: "EN", + }, + } + ); + + const poi: PointOfInterest = POIModelToEntity(dataES); + poi.contentEN = dataEN.content; + poi.directionsEN = dataEN.directions; + + return poi; + } + + /** + * Generates a PDF for the specified points of interest. + * @param idPlace - The ID of the place. + * @param pointsId - An array of point IDs to include in the PDF. + * @returns A promise that resolves to a base64-encoded string of the PDF. + */ + async getPDFByPoints(idPlace: number, pointsId: number[]): Promise { + const { data } = await axios.get( + APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT + "/generate", + { + params: { + pointsId: pointsId.join(","), + }, + responseType: "arraybuffer", + } + ); + return Buffer.from(data, "binary").toString("base64"); + } +} diff --git a/web/src/data/datasource/api/town_datasource.ts b/web/src/data/datasource/api/town_datasource.ts new file mode 100644 index 00000000..b99259e9 --- /dev/null +++ b/web/src/data/datasource/api/town_datasource.ts @@ -0,0 +1,115 @@ +import axios from "axios"; +import { APIUrl } from "../../../core/constants/api_url"; +import { TownDatasourceInf } from "../town_datasource"; +import { State } from "./entities/state"; +import { Town } from "./entities/town"; +import { StateModel } from "../../../domain/model/StateModel"; +import { TownModelTrad, TownModel } from "../../../domain/model/TownModel"; +import { API_ROUTE_STATE } from "../../../core/constants/api_routes"; + +export class TownDatasourceProd implements TownDatasourceInf { + /** + * Retrieves a list of states from the API. + * @returns A promise that resolves to an array of State objects. + */ + async getStates(): Promise { + const { data } = await axios.get (APIUrl + API_ROUTE_STATE); + const states = data.map((value) => { + const state: State = { + stateId: value.stateId, + name: value.name, + imageURL: value.imageURL, + }; + return state; + }); + + return states; + } + + /** + * Registers a new town using the provided form data. + * @param form - The town data to be registered. + * @returns A promise that resolves when the town is successfully registered. + */ + async registerTown(form: Town): Promise { + const formToSend = new FormData(); + formToSend.append("name", form.name); + formToSend.append("descriptionES", form.descriptionES || ""); + formToSend.append("descriptionEN", form.descriptionEN || ""); + formToSend.append("state", String(form.idState)); + formToSend.append("image", form.imageURL || ""); + + const headers = { + "Content-Type": "multipart/form-data", + }; + + await axios.post(APIUrl + "/town", formToSend, { headers }); + } + + /** + * Retrieves a list of towns by state ID and state name. + * @param idState - The ID of the state. + * @param stateName - The name of the state. + * @returns A promise that resolves to an array of Town objects. + */ + async getTownsByState(idState: number, stateName: string): Promise { + const { data } = await axios.get ( + APIUrl + `/state/${idState}/town`, + { + params: { + lang: "ES", + }, + } + ); + const towns = data.map((value) => { + const town: Town = { + idTown: value.townId, + name: value.name, + idState: value.stateId, + state: stateName, + }; + return town; + }); + + return towns; + } + + /** + * Retrieves a town by its ID. + * @param idTown - The ID of the town. + * @returns A promise that resolves to a Town object. + */ + async getTown(idTown: number): Promise { + const { data } = await axios.get (APIUrl + `/town/${idTown}`); + const town: Town = { + idTown: data.townId, + name: data.name, + idState: data.stateId, + descriptionES: data.descriptionES, + descriptionEN: data.descriptionEN, + state: "", + imageURL: data.imageName, + }; + return town; + } + + /** + * Updates an existing town using the provided form data. + * @param form - The town data to be updated. + * @returns A promise that resolves when the town is successfully updated. + */ + async updateTown(form: Town): Promise { + const formToSend = new FormData(); + formToSend.append("name", form.name); + formToSend.append("descriptionES", form.descriptionES || ""); + formToSend.append("descriptionEN", form.descriptionEN || ""); + formToSend.append("image", form.imageURL || ""); + formToSend.append("state", String(form.idState)); + + const headers = { + "Content-Type": "multipart/form-data", + }; + + await axios.patch(APIUrl + `/town/${form.idTown}`, formToSend, { headers }); + } +} diff --git a/web/src/data/datasource/category_datasource.ts b/web/src/data/datasource/category_datasource.ts new file mode 100644 index 00000000..1f207247 --- /dev/null +++ b/web/src/data/datasource/category_datasource.ts @@ -0,0 +1,26 @@ +import { Category, CategoryFormValues } from "./api/entities/category"; + +/** + * Interface representing a data source for handling category-related operations. + */ +export interface CategoryDatasourceInf { + /** + * Registers a new category. + * @param form - The category data to register. + * @returns A promise that resolves when the registration is complete. + */ + registerCategory(form: CategoryFormValues): Promise ; + + /** + * Retrieves a list of categories. + * @returns A promise that resolves to an array of Category objects. + */ + getCategories(): Promise ; + + /** + * Deletes an existing category. + * @param category - The category to delete. + * @returns A promise that resolves when the deletion is complete. + */ + deleteCategory(category: Category): Promise ; +} diff --git a/web/src/data/datasource/login_datasource.ts b/web/src/data/datasource/login_datasource.ts new file mode 100644 index 00000000..69a04888 --- /dev/null +++ b/web/src/data/datasource/login_datasource.ts @@ -0,0 +1,14 @@ +import { LoginFormValues } from "./api/entities/login_form_values"; +import { LoggedInUser } from "./api/entities/user"; + +/** + * Interface representing a data source for handling login operations. + */ +export interface LoginDatasource { + /** + * Retrieves a token for the given login form values. + * @param form - The login form values. + * @returns A promise that resolves to a LoggedInUser object containing the token. + */ + getToken(form: LoginFormValues): Promise ; +} diff --git a/web/src/data/datasource/place_datasource.ts b/web/src/data/datasource/place_datasource.ts new file mode 100644 index 00000000..3b787935 --- /dev/null +++ b/web/src/data/datasource/place_datasource.ts @@ -0,0 +1,34 @@ +import { Place } from "./api/entities/place"; + +/** + * Interface representing a data source for handling place-related operations. + */ +export interface PlaceDatasourceInf { + /** + * Registers a new place. + * @param form - The place data to register. + * @returns A promise that resolves when the registration is complete. + */ + registerPlace(form: Place): Promise ; + + /** + * Retrieves a list of places by town. + * @param idTown - The ID of the town. + * @returns A promise that resolves to an array of Place objects. + */ + getPlacesByTown(idTown: number): Promise ; + + /** + * Retrieves a place by its ID. + * @param idPlace - The ID of the place. + * @returns A promise that resolves to a Place object. + */ + getPlaceById(idPlace: number): Promise ; + + /** + * Updates an existing place. + * @param place - The updated place data. + * @returns A promise that resolves when the update is complete. + */ + updatePlace(place: Place): Promise ; +} diff --git a/web/src/data/datasource/poi_datasource.ts b/web/src/data/datasource/poi_datasource.ts new file mode 100644 index 00000000..b03b50dd --- /dev/null +++ b/web/src/data/datasource/poi_datasource.ts @@ -0,0 +1,35 @@ +import { PointOfInterest } from "./api/entities/poi"; + +/** + * Interface representing a data source for handling points of interest (POI) operations. + */ +export interface PoiDatasourceInf { + /** + * Registers a new point of interest. + * @param form - The POI data to register. + * @returns A promise that resolves when the registration is complete. + */ + registerPoint(form: PointOfInterest): Promise ; + + /** + * Retrieves a list of POIs by place. + * @param idPlace - The ID of the place. + * @returns A promise that resolves to an array of PointOfInterest objects. + */ + getPOIsByPlace(idPlace: number): Promise ; + + /** + * Retrieves a POI by its ID. + * @param idPoint - The ID of the POI. + * @returns A promise that resolves to a PointOfInterest object. + */ + getPOIById(idPoint: number): Promise ; + + /** + * Retrieves a PDF document containing information about specified POIs. + * @param idPlace - The ID of the place. + * @param pointsId - An array of POI IDs. + * @returns A promise that resolves to a string representing the PDF document. + */ + getPDFByPoints(idPlace: number, pointsId: number[]): Promise ; +} diff --git a/web/src/data/datasource/town_datasource.ts b/web/src/data/datasource/town_datasource.ts new file mode 100644 index 00000000..87fa51c5 --- /dev/null +++ b/web/src/data/datasource/town_datasource.ts @@ -0,0 +1,41 @@ +import { State } from "./api/entities/state"; +import { Town } from "./api/entities/town"; + +/** + * Interface representing a data source for handling town-related operations. + */ +export interface TownDatasourceInf { + /** + * Retrieves a list of states. + * @returns A promise that resolves to an array of State objects. + */ + getStates(): Promise ; + + /** + * Registers a new town. + * @param form - The town data to register. + */ + registerTown(form: Town): void; + + /** + * Retrieves a list of towns by state. + * @param idState - The ID of the state. + * @param stateName - The name of the state. + * @returns A promise that resolves to an array of Town objects. + */ + getTownsByState(idState: number, stateName: string): Promise ; + + /** + * Retrieves a town by its ID. + * @param idTown - The ID of the town. + * @returns A promise that resolves to a Town object. + */ + getTown(idTown: number): Promise ; + + /** + * Updates an existing town. + * @param form - The updated town data. + * @returns A promise that resolves when the update is complete. + */ + updateTown(form: Town): Promise ; +} diff --git a/web/src/data/datasources/prod/category_datasource.ts b/web/src/data/datasources/prod/category_datasource.ts deleted file mode 100644 index 41271b55..00000000 --- a/web/src/data/datasources/prod/category_datasource.ts +++ /dev/null @@ -1,45 +0,0 @@ -import axios from "axios"; -import { CategoryDatasourceInf } from "../../../infraestructure/datasources/category_datasource"; -import { Category, CategoryFormValues } from "../../../infraestructure/entities/category"; -import { CategoryModel } from "../../models/prod/CategoryModel"; -import { APIUrl } from "../../../constants/api_url"; - -export class CategoryDatasourceProd implements CategoryDatasourceInf{ - async registerCategory(form: CategoryFormValues): Promise { - await axios.post( - APIUrl + "/category", - { - nameES: form.nameES, - nameEN: form.nameEN - } - ); - } - - async getCategories(): Promise { - const {data: dataES} = await axios.get (APIUrl+'/category/', { - params: { - lang: 'ES' - } - }); - const {data: dataEN} = await axios.get (APIUrl+'/category/', { - params: { - lang: 'EN' - } - }); - const categories : Category[] = []; - for(let i=0; i { - await axios.delete(APIUrl + `/category/${category.idCategory}`) - } -} \ No newline at end of file diff --git a/web/src/data/datasources/prod/login_datasource.ts b/web/src/data/datasources/prod/login_datasource.ts deleted file mode 100644 index c2d7f535..00000000 --- a/web/src/data/datasources/prod/login_datasource.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { LoginDatasourceInf } from "../../../infraestructure/datasources/login_datasource"; -import { LoginFormValues } from "../../../infraestructure/entities/login_form_values"; -import axios from "axios"; -import { LoggedInUser } from "../../../infraestructure/entities/user"; -import { LoggedInUserModel } from "../../models/prod/LoggedInUserModel"; -import { UserRole } from "../../../constants/roles"; -import { APIUrl } from "../../../constants/api_url"; - -export class LoginDatasourceProd implements LoginDatasourceInf{ - async getToken(form: LoginFormValues): Promise { - const {email, password} = form; - const {data} = await axios.post ( - APIUrl + "/admin/signin", - { - email: email, - password: password, - } - ); - const user: LoggedInUser = { - user: { - email: data.email, - name: data.name, - role: data.role === UserRole.SUPERADMIN ? UserRole.SUPERADMIN : UserRole.ADMIN, - }, - token: data.token, - }; - - return user; - } -} \ No newline at end of file diff --git a/web/src/data/datasources/prod/place_datasource.ts b/web/src/data/datasources/prod/place_datasource.ts deleted file mode 100644 index 299676c5..00000000 --- a/web/src/data/datasources/prod/place_datasource.ts +++ /dev/null @@ -1,94 +0,0 @@ -import axios from "axios"; -import { APIUrl } from "../../../constants/api_url"; -import { PlaceDatasourceInf } from "../../../infraestructure/datasources/place_datasource"; -import { AvailableDays, Place } from "../../../infraestructure/entities/place"; -import { PlaceModel, placeModelToEntity } from "../../models/prod/PlaceModel"; - -export class PlaceDatasourceProd implements PlaceDatasourceInf{ - async registerPlace(form: Place): Promise { - const formToSend = new FormData(); - formToSend.append('available', form.available); - formToSend.append('idTown', String(form.idTown)); - formToSend.append('name', form.name); - formToSend.append('categoriesId', form.categoriesId.join(',')); - formToSend.append('descriptionES', form.descriptions?.[0] ?? ''); - formToSend.append('descriptionEN', form.descriptions?.[1] ?? ''); - formToSend.append('image', form.imagesList?.[0] ?? ''); - formToSend.append('latitude', String(form.latitude)); - formToSend.append('longitude', String(form.longitude)); - formToSend.append('openAt', String(form.openAt)); - formToSend.append('closeAt', String(form.closeAt)); - formToSend.append('address', form.address); - - if(form.available === AvailableDays.CUSTOM){ - formToSend.append('startDate', String(form.startDate)); - formToSend.append('endDate', String(form.endDate)); - } - - const headers = { - 'Content-Type': 'multipart/form-data' - }; - - await axios.post(APIUrl + '/place', formToSend,{headers}); - } - - async getPlacesByTown(idTown: number): Promise { - const {data} = await axios.get (APIUrl+`/place/town/${idTown}/place`, { - params: { - lang: 'ES' - } - }); - - const places = data.map((dataES) => { - return placeModelToEntity(dataES); - }) - - return places; - } - - async getPlaceById(idPlace: number): Promise { - const {data: dataES} = await axios.get (APIUrl+`/place/${idPlace}`, { - params: { - lang: 'ES' - } - }); - - const {data: dataEN} = await axios.get (APIUrl+`/place/${idPlace}`, { - params: { - lang: 'EN' - } - }); - - const place: Place = placeModelToEntity(dataES); - place.descriptions?.push(dataEN.description); - - return place; - } - - async updatePlace(place: Place): Promise { - const formToSend = new FormData(); - formToSend.append('available', place.available); - formToSend.append('idTown', String(place.idTown)); - formToSend.append('name', place.name); - formToSend.append('categoriesId', place.categoriesId.join(',')); - formToSend.append('descriptionES', place.descriptions?.[0] ?? ''); - formToSend.append('descriptionEN', place.descriptions?.[1] ?? ''); - formToSend.append('image', place.imagesList?.[0] ?? ''); - formToSend.append('latitude', String(place.latitude)); - formToSend.append('longitude', String(place.longitude)); - formToSend.append('openAt', String(place.openAt)); - formToSend.append('closeAt', String(place.closeAt)); - formToSend.append('address', place.address); - - if(place.available === AvailableDays.CUSTOM){ - formToSend.append('startDate', String(place.startDate)); - formToSend.append('endDate', String(place.endDate)); - } - - const headers = { - 'Content-Type': 'multipart/form-data' - }; - - await axios.patch(APIUrl+`/place/${place.idPlace}`, formToSend,{headers}); - } -} \ No newline at end of file diff --git a/web/src/data/datasources/prod/poi_datasource.ts b/web/src/data/datasources/prod/poi_datasource.ts deleted file mode 100644 index f1d6b92b..00000000 --- a/web/src/data/datasources/prod/poi_datasource.ts +++ /dev/null @@ -1,70 +0,0 @@ -import axios from "axios"; -import { Buffer } from "buffer"; -import { PoiDatasourceInf } from "../../../infraestructure/datasources/poi_datasource"; -import { PointOfInterest } from "../../../infraestructure/entities/poi"; -import { APIUrl } from "../../../constants/api_url"; -import { API_ROUTE_PLACE, API_ROUTE_POINT } from "../../../constants/api_routes"; -import { POIModel, POIModelToEntity } from "../../models/prod/POIModel"; - -export class POIDatasourceProd implements PoiDatasourceInf{ - async registerPoint(form: PointOfInterest): Promise { - const formToSend = new FormData(); - formToSend.append('idPlace', String(form.idPlace)); - formToSend.append('name', form.name); - formToSend.append('image', form.image); - formToSend.append('contentEN', form.contentEN); - formToSend.append('contentES', form.contentES); - formToSend.append('directionsEN', form.directionsEN); - formToSend.append('directionsES', form.directionsES); - - const headers = { - 'Content-Type': 'multipart/form-data' - }; - - await axios.post(APIUrl + API_ROUTE_POINT, formToSend,{headers}); - } - - async getPOIsByPlace(idPlace: number): Promise { - const {data: dataES} = await axios.get (APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT, { - params: { - lang: 'ES' - } - }); - - const poiList = dataES.map((dataESModel) => { - return POIModelToEntity(dataESModel); - }) - - return poiList; - } - - async getPOIById(idPoint: number): Promise { - const {data: dataES} = await axios.get (APIUrl + API_ROUTE_POINT + `/${idPoint}`, { - params: { - lang: 'ES' - } - }); - - const {data: dataEN} = await axios.get (APIUrl + API_ROUTE_POINT + `/${idPoint}`, { - params: { - lang: 'EN' - } - }); - - const poi: PointOfInterest = POIModelToEntity(dataES); - poi.contentEN = dataEN.content; - poi.directionsEN = dataEN.directions; - - return poi; - } - - async getPDFByPoints(idPlace: number, pointsId: number[]): Promise { - const {data} = await axios.get(APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT + '/generate', { - params: { - pointsId: pointsId.join(',') - }, - responseType: 'arraybuffer' - }); - return Buffer.from(data, 'binary').toString('base64'); - } -} \ No newline at end of file diff --git a/web/src/data/datasources/prod/town_datasource.ts b/web/src/data/datasources/prod/town_datasource.ts deleted file mode 100644 index fcbba15e..00000000 --- a/web/src/data/datasources/prod/town_datasource.ts +++ /dev/null @@ -1,86 +0,0 @@ -import axios from "axios"; -import { APIUrl } from "../../../constants/api_url"; -import { TownDatasourceInf } from "../../../infraestructure/datasources/town_datasource"; -import { StateModel } from "../../models/prod/StateModel"; -import { State } from "../../../infraestructure/entities/state"; -import { Town } from "../../../infraestructure/entities/town"; -import { TownModel, TownModelTrad } from "../../models/prod/TownModel"; - -export class TownDatasourceProd implements TownDatasourceInf{ - async getStates(): Promise { - const {data} = await axios.get (APIUrl+"/state"); - const states = data.map((value) => { - const state: State = { - stateId : value.stateId, - name: value.name, - imageURL: value.imageURL - } - return state; - }) - - return states; - } - - async registerTown(form: Town): Promise { - const formToSend = new FormData(); - formToSend.append('name',form.name); - formToSend.append('descriptionES',form.descriptionES || ''); - formToSend.append('descriptionEN',form.descriptionEN || ''); - formToSend.append('state', String(form.idState)); - formToSend.append('image',form.imageURL || ''); - - const headers = { - 'Content-Type': 'multipart/form-data' - }; - - await axios.post(APIUrl + '/town', formToSend,{headers}); - } - - async getTownsByState(idState: number, stateName:string): Promise { - const {data} = await axios.get (APIUrl+`/state/${idState}/town`, { - params: { - lang: 'ES' - } - }); - const towns = data.map((value) => { - const town: Town = { - idTown : value.townId, - name: value.name, - idState: value.stateId, - state: stateName - } - return town; - }) - - return towns; - } - - async getTown(idTown: number): Promise { - const {data} = await axios.get (APIUrl+`/town/${idTown}`); - const town: Town = { - idTown : data.townId, - name: data.name, - idState: data.stateId, - descriptionES: data.descriptionES, - descriptionEN: data.descriptionEN, - state: '', - imageURL: data.imageName - } - return town; - } - - async updateTown(form: Town): Promise { - const formToSend = new FormData(); - formToSend.append('name',form.name); - formToSend.append('descriptionES',form.descriptionES || ''); - formToSend.append('descriptionEN',form.descriptionEN || ''); - formToSend.append('image',form.imageURL || ''); - formToSend.append('state', String(form.idState)); - - const headers = { - 'Content-Type': 'multipart/form-data' - }; - - await axios.patch(APIUrl+`/town/${form.idTown}`, formToSend,{headers}); - } -} \ No newline at end of file diff --git a/web/src/data/models/prod/AdminModel.ts b/web/src/data/models/prod/AdminModel.ts deleted file mode 100644 index 2ac2cfc4..00000000 --- a/web/src/data/models/prod/AdminModel.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface AdminModel { - email: string; - name: string; - lastName: string; - role?: string; - idTown?: number; - status: string; -} \ No newline at end of file diff --git a/web/src/data/models/prod/CategoryModel.ts b/web/src/data/models/prod/CategoryModel.ts deleted file mode 100644 index 2846a79c..00000000 --- a/web/src/data/models/prod/CategoryModel.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface CategoryModel{ - idCategory: number; - name: string; -} - -export interface CategoryModelLan { - idCategory: number; - language: string; - name: string; -} \ No newline at end of file diff --git a/web/src/data/models/prod/LoggedInUserModel.ts b/web/src/data/models/prod/LoggedInUserModel.ts deleted file mode 100644 index 8f73d45b..00000000 --- a/web/src/data/models/prod/LoggedInUserModel.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface LoggedInUserModel { - email: string; - name: string; - role: string; - token: string; -} \ No newline at end of file diff --git a/web/src/data/models/prod/POIModel.ts b/web/src/data/models/prod/POIModel.ts deleted file mode 100644 index 603b8bd4..00000000 --- a/web/src/data/models/prod/POIModel.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PointOfInterest } from "../../../infraestructure/entities/poi"; - -export interface POIModel { - idPoint: number; - idPlace: number; - name: string; - imageName: string; - content: string; - directions: string; -} - -export const POIModelToEntity = (model: POIModel) =>{ - const poi: PointOfInterest = { - idPoint : model.idPoint, - idPlace : model.idPlace, - name: model.name, - image: model.imageName, - contentES: model.content, - contentEN: model.content, - directionsES: model.directions, - directionsEN: model.directions - } - return poi; -} \ No newline at end of file diff --git a/web/src/data/models/prod/PlaceModel.ts b/web/src/data/models/prod/PlaceModel.ts deleted file mode 100644 index 5e4ea3e4..00000000 --- a/web/src/data/models/prod/PlaceModel.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { AvailableDays, Place } from "../../../infraestructure/entities/place"; -import { CategoryModelLan } from "./CategoryModel"; - -export interface PlaceModel { - idTown: number; - idPlace: number; - available: string; - description: string; - latitude: number; - longitude: number; - imageName: string; - name: string; - categories: CategoryModelLan[] - openAt: number; - closeAt: number; - startDate?: Date; - endDate?: Date; - address: string; -} - -export const placeModelToEntity = (model: PlaceModel) =>{ - let availableDays = AvailableDays.WEEKEND; - switch(model.available){ - case AvailableDays.ALL_DAYS: - availableDays = AvailableDays.ALL_DAYS; - break; - case AvailableDays.CUSTOM: - availableDays = AvailableDays.CUSTOM; - break; - case AvailableDays.WEEKDAYS: - availableDays = AvailableDays.WEEKDAYS; - break; - default: - availableDays = AvailableDays.WEEKEND; - break; - } - - const place: Place = { - idTown : model.idTown, - idPlace : model.idPlace, - available : availableDays, - latitude: model.latitude, - longitude: model.longitude, - descriptions: [model.description], - imagesList: [model.imageName], - name: model.name, - categoriesId: model.categories.map((category)=> category.idCategory), - openAt: model.openAt, - closeAt: model.closeAt, - startDate: model.startDate, - endDate: model.endDate, - address: model.address - } - return place; -} \ No newline at end of file diff --git a/web/src/data/models/prod/StateModel.ts b/web/src/data/models/prod/StateModel.ts deleted file mode 100644 index 41f2f827..00000000 --- a/web/src/data/models/prod/StateModel.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface StateModel { - stateId: number; - name: string; - imageURL: string; -} \ No newline at end of file diff --git a/web/src/data/models/prod/TownModel.ts b/web/src/data/models/prod/TownModel.ts deleted file mode 100644 index 4b79e916..00000000 --- a/web/src/data/models/prod/TownModel.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface TownModelTrad { - townId: number; - name : string; - imageName : string; - description : string; - stateId : number; -} - -export interface TownModel { - townId: number; - name : string; - descriptionEN : string; - descriptionES : string; - imageName : string; - stateId : number; -} \ No newline at end of file diff --git a/web/src/data/repositories/prod/admin_repository.ts b/web/src/data/repositories/prod/admin_repository.ts deleted file mode 100644 index b86b4da1..00000000 --- a/web/src/data/repositories/prod/admin_repository.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { AdminDatasourceInf } from "../../../infraestructure/datasources/admin_datasource"; -import { - Admin, - AdminFormValues, -} from "../../../infraestructure/entities/admin_form_values"; -import { ResetPasswordValues } from "../../../infraestructure/entities/reset_password_values"; -import { AdminRepositoryInf } from "../../../infraestructure/repositories/admin_repository"; - -export class AdminRepositoryProd implements AdminRepositoryInf { - constructor(private datasource: AdminDatasourceInf) {} - - async registerAdmin(form: AdminFormValues): Promise { - return this.datasource.registerAdmin(form); - } - - async getAdminInfo(token: string): Promise { - return this.datasource.getAdminInfo(token); - } - - async changePassword( - token: string, - prevPassword: string, - newPassword: string - ): Promise { - return this.datasource.changePassword(token, prevPassword, newPassword); - } - - async getAdminsByTown(idTown: number): Promise { - return this.datasource.getAdminsByTown(idTown); - } - - async generateResetCode(email: string): Promise { - return this.datasource.generateResetCode(email); - } - - async resetPassword(form: ResetPasswordValues): Promise { - return this.datasource.resetPassword(form); - } -} diff --git a/web/src/data/repositories/prod/category_repository.ts b/web/src/data/repositories/prod/category_repository.ts deleted file mode 100644 index ab0055eb..00000000 --- a/web/src/data/repositories/prod/category_repository.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CategoryDatasourceInf } from "../../../infraestructure/datasources/category_datasource"; -import { Category, CategoryFormValues } from "../../../infraestructure/entities/category"; -import { CategoryRepositoryInf } from "../../../infraestructure/repositories/category_repository"; - -export class CategoryRepositoryProd implements CategoryRepositoryInf{ - constructor( - private datasource: CategoryDatasourceInf - ){} - - async registerCategory(form: CategoryFormValues): Promise { - return this.datasource.registerCategory(form); - } - - async getCategories(): Promise { - return this.datasource.getCategories(); - } - - async deleteCategory(category: Category): Promise { - return this.datasource.deleteCategory(category); - } -} \ No newline at end of file diff --git a/web/src/data/repositories/prod/login_repository.ts b/web/src/data/repositories/prod/login_repository.ts deleted file mode 100644 index 69c0694f..00000000 --- a/web/src/data/repositories/prod/login_repository.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { LoginDatasourceInf } from "../../../infraestructure/datasources/login_datasource"; -import { LoginFormValues } from "../../../infraestructure/entities/login_form_values"; -import { LoggedInUser } from "../../../infraestructure/entities/user"; -import { LoginRepositoryInf } from "../../../infraestructure/repositories/login_repository"; - -export class LoginRepositoryProd implements LoginRepositoryInf{ - constructor( - private datasource: LoginDatasourceInf - ){} - async getToken(form: LoginFormValues): Promise { - return this.datasource.getToken(form); - } -} \ No newline at end of file diff --git a/web/src/data/repositories/prod/place_repository.ts b/web/src/data/repositories/prod/place_repository.ts deleted file mode 100644 index 843fdb8d..00000000 --- a/web/src/data/repositories/prod/place_repository.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PlaceDatasourceInf } from "../../../infraestructure/datasources/place_datasource"; -import { Place } from "../../../infraestructure/entities/place"; -import { PlaceRepositoryInf } from "../../../infraestructure/repositories/place_repository"; - -export class PlaceRepositoryProd implements PlaceRepositoryInf{ - constructor( - private datasouce: PlaceDatasourceInf - ){} - async registerPlace(form: Place): Promise { - return this.datasouce.registerPlace(form); - } - - async getPlacesByTown(idTown: number): Promise { - return this.datasouce.getPlacesByTown(idTown); - } - - async getPlaceById(idPlace: number): Promise { - return this.datasouce.getPlaceById(idPlace); - } - - async updatePlace(place: Place): Promise { - return this.datasouce.updatePlace(place); - } -} \ No newline at end of file diff --git a/web/src/data/repositories/prod/poi_repository.ts b/web/src/data/repositories/prod/poi_repository.ts deleted file mode 100644 index 86a180bd..00000000 --- a/web/src/data/repositories/prod/poi_repository.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { PoiDatasourceInf } from "../../../infraestructure/datasources/poi_datasource"; -import { PointOfInterest } from "../../../infraestructure/entities/poi"; -import { PoiRepositoryInf } from "../../../infraestructure/repositories/poi_repository"; - -export class POIRepositoryProd implements PoiRepositoryInf{ - constructor( - private datasouce: PoiDatasourceInf - ){} - - async registerPoint(form: PointOfInterest): Promise { - return this.datasouce.registerPoint(form); - } - - async getPOIById(idPoint: number): Promise { - return this.datasouce.getPOIById(idPoint); - } - - async getPOIsByPlace(idPlace: number): Promise { - return this.datasouce.getPOIsByPlace(idPlace); - } - - async getPDFByPoints(idPlace: number, pointsId: number[]): Promise { - return this.datasouce.getPDFByPoints(idPlace, pointsId); - } -} \ No newline at end of file diff --git a/web/src/data/repositories/prod/town_repository.ts b/web/src/data/repositories/prod/town_repository.ts deleted file mode 100644 index 72996d29..00000000 --- a/web/src/data/repositories/prod/town_repository.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { TownDatasourceInf } from "../../../infraestructure/datasources/town_datasource"; -import { State } from "../../../infraestructure/entities/state"; -import { Town } from "../../../infraestructure/entities/town"; -import { TownRepositoryInf } from "../../../infraestructure/repositories/town_repository"; - -export class TownRepositoryProd implements TownRepositoryInf{ - constructor( - private datasource: TownDatasourceInf - ){} - async getStates(): Promise { - return this.datasource.getStates(); - } - async registerTown(form: Town): Promise { - return this.datasource.registerTown(form); - } - async getTownsByState(idState: number, stateName:string) : Promise { - return this.datasource.getTownsByState(idState, stateName); - } - async getTown(idTown: number): Promise { - return this.datasource.getTown(idTown); - } - async updateTown(form: Town): Promise { - return this.datasource.updateTown(form); - } -} \ No newline at end of file diff --git a/web/src/data/repository/admin_repository.ts b/web/src/data/repository/admin_repository.ts new file mode 100644 index 00000000..e2ceedcb --- /dev/null +++ b/web/src/data/repository/admin_repository.ts @@ -0,0 +1,74 @@ +import { AdminDatasourceInf } from "../datasource/admin_datasource"; +import { + Admin, + AdminFormValues, +} from "../datasource/api/entities/admin_form_values"; +import { ResetPasswordValues } from "../datasource/api/entities/reset_password_values"; +import { AdminRepositoryInf } from "../../domain/repository/admin_repository"; + +/** + * Implementation of the AdminRepository interface for production. + */ +export class AdminRepositoryProd implements AdminRepositoryInf { + constructor(private datasource: AdminDatasourceInf) {} + + /** + * Registers a new admin. + * @param form - The admin data to register. + * @returns A promise that resolves when the admin is registered. + */ + async registerAdmin(form: AdminFormValues): Promise { + return this.datasource.registerAdmin(form); + } + + /** + * Retrieves admin information by token. + * @param token - The token of the admin. + * @returns A promise that resolves to an Admin object. + */ + async getAdminInfo(token: string): Promise { + return this.datasource.getAdminInfo(token); + } + + /** + * Changes the password of an admin. + * @param token - The token of the admin. + * @param prevPassword - The previous password. + * @param newPassword - The new password. + * @returns A promise that resolves when the password is changed. + */ + async changePassword( + token: string, + prevPassword: string, + newPassword: string + ): Promise { + return this.datasource.changePassword(token, prevPassword, newPassword); + } + + /** + * Retrieves admins by town. + * @param idTown - The ID of the town. + * @returns A promise that resolves to an array of Admin objects. + */ + async getAdminsByTown(idTown: number): Promise { + return this.datasource.getAdminsByTown(idTown); + } + + /** + * Generates a reset code for the given email. + * @param email - The email to generate the reset code for. + * @returns A promise that resolves when the reset code is generated. + */ + async generateResetCode(email: string): Promise { + return this.datasource.generateResetCode(email); + } + + /** + * Resets the password using the given form values. + * @param form - The reset password form values. + * @returns A promise that resolves when the password is reset. + */ + async resetPassword(form: ResetPasswordValues): Promise { + return this.datasource.resetPassword(form); + } +} diff --git a/web/src/data/repository/category_repository.ts b/web/src/data/repository/category_repository.ts new file mode 100644 index 00000000..d35aa5fa --- /dev/null +++ b/web/src/data/repository/category_repository.ts @@ -0,0 +1,39 @@ +import { CategoryDatasourceInf } from "../datasource/category_datasource"; +import { + Category, + CategoryFormValues, +} from "../datasource/api/entities/category"; +import { CategoryRepositoryInf } from "../../domain/repository/category_repository"; + +/** + * Implementation of the CategoryRepository interface for production. + */ +export class CategoryRepositoryProd implements CategoryRepositoryInf { + constructor(private datasource: CategoryDatasourceInf) {} + + /** + * Registers a new category. + * @param form - The category data to register. + * @returns A promise that resolves when the category is registered. + */ + async registerCategory(form: CategoryFormValues): Promise { + return this.datasource.registerCategory(form); + } + + /** + * Retrieves all categories. + * @returns A promise that resolves to an array of Category objects. + */ + async getCategories(): Promise { + return this.datasource.getCategories(); + } + + /** + * Deletes an existing category. + * @param category - The category to delete. + * @returns A promise that resolves when the category is deleted. + */ + async deleteCategory(category: Category): Promise { + return this.datasource.deleteCategory(category); + } +} diff --git a/web/src/data/repository/login_repository.ts b/web/src/data/repository/login_repository.ts new file mode 100644 index 00000000..4dac9d5b --- /dev/null +++ b/web/src/data/repository/login_repository.ts @@ -0,0 +1,20 @@ +import { LoginDatasource } from "../datasource/login_datasource"; +import { LoginFormValues } from "../datasource/api/entities/login_form_values"; +import { LoggedInUser } from "../datasource/api/entities/user"; +import { LoginRepository } from "../../domain/repository/login_repository"; + +/** + * Implementation of the LoginRepository interface. + */ +export class LoginRepositoryImpl implements LoginRepository { + constructor(private datasource: LoginDatasource) {} + + /** + * Retrieves a token for the given login form values. + * @param form - The login form values. + * @returns A promise that resolves to a logged-in user. + */ + async getToken(form: LoginFormValues): Promise { + return this.datasource.getToken(form); + } +} diff --git a/web/src/data/repository/place_repository.ts b/web/src/data/repository/place_repository.ts new file mode 100644 index 00000000..aa120f13 --- /dev/null +++ b/web/src/data/repository/place_repository.ts @@ -0,0 +1,46 @@ +import { PlaceDatasourceInf } from "../datasource/place_datasource"; +import { Place } from "../datasource/api/entities/place"; +import { PlaceRepositoryInf } from "../../domain/repository/place_repository"; + +/** + * Implementation of the PlaceRepository interface for production. + */ +export class PlaceRepositoryProd implements PlaceRepositoryInf { + constructor(private datasouce: PlaceDatasourceInf) {} + + /** + * Registers a new place. + * @param form - The place data to register. + * @returns A promise that resolves when the place is registered. + */ + async registerPlace(form: Place): Promise { + return this.datasouce.registerPlace(form); + } + + /** + * Retrieves places by town. + * @param idTown - The ID of the town. + * @returns A promise that resolves to an array of Place objects. + */ + async getPlacesByTown(idTown: number): Promise { + return this.datasouce.getPlacesByTown(idTown); + } + + /** + * Retrieves a place by its ID. + * @param idPlace - The ID of the place. + * @returns A promise that resolves to a Place object. + */ + async getPlaceById(idPlace: number): Promise { + return this.datasouce.getPlaceById(idPlace); + } + + /** + * Updates an existing place. + * @param place - The place data to update. + * @returns A promise that resolves when the place is updated. + */ + async updatePlace(place: Place): Promise { + return this.datasouce.updatePlace(place); + } +} diff --git a/web/src/data/repository/poi_repository.ts b/web/src/data/repository/poi_repository.ts new file mode 100644 index 00000000..9a59ed06 --- /dev/null +++ b/web/src/data/repository/poi_repository.ts @@ -0,0 +1,47 @@ +import { PoiDatasourceInf } from "../datasource/poi_datasource"; +import { PointOfInterest } from "../datasource/api/entities/poi"; +import { PoiRepositoryInf } from "../../domain/repository/poi_repository"; + +/** + * Implementation of the PoiRepository interface for production. + */ +export class POIRepositoryProd implements PoiRepositoryInf { + constructor(private datasouce: PoiDatasourceInf) {} + + /** + * Registers a new point of interest. + * @param form - The point of interest data to register. + * @returns A promise that resolves when the point of interest is registered. + */ + async registerPoint(form: PointOfInterest): Promise { + return this.datasouce.registerPoint(form); + } + + /** + * Retrieves a point of interest by its ID. + * @param idPoint - The ID of the point of interest. + * @returns A promise that resolves to a PointOfInterest object. + */ + async getPOIById(idPoint: number): Promise { + return this.datasouce.getPOIById(idPoint); + } + + /** + * Retrieves points of interest by place. + * @param idPlace - The ID of the place. + * @returns A promise that resolves to an array of PointOfInterest objects. + */ + async getPOIsByPlace(idPlace: number): Promise { + return this.datasouce.getPOIsByPlace(idPlace); + } + + /** + * Retrieves a PDF document for the given points of interest. + * @param idPlace - The ID of the place. + * @param pointsId - An array of point IDs. + * @returns A promise that resolves to a string representing the PDF document. + */ + async getPDFByPoints(idPlace: number, pointsId: number[]): Promise { + return this.datasouce.getPDFByPoints(idPlace, pointsId); + } +} diff --git a/web/src/data/repository/town_repository.ts b/web/src/data/repository/town_repository.ts new file mode 100644 index 00000000..1eb7ddb8 --- /dev/null +++ b/web/src/data/repository/town_repository.ts @@ -0,0 +1,56 @@ +import { TownDatasourceInf } from "../datasource/town_datasource"; +import { State } from "../datasource/api/entities/state"; +import { Town } from "../datasource/api/entities/town"; +import { TownRepositoryInf } from "../../domain/repository/town_repository"; + +/** + * Implementation of the TownRepository interface for production. + */ +export class TownRepositoryProd implements TownRepositoryInf { + constructor(private datasource: TownDatasourceInf) {} + + /** + * Retrieves all states. + * @returns A promise that resolves to an array of State objects. + */ + async getStates(): Promise { + return this.datasource.getStates(); + } + + /** + * Registers a new town. + * @param form - The town data to register. + * @returns A promise that resolves when the town is registered. + */ + async registerTown(form: Town): Promise { + return this.datasource.registerTown(form); + } + + /** + * Retrieves towns by state. + * @param idState - The ID of the state. + * @param stateName - The name of the state. + * @returns A promise that resolves to an array of Town objects. + */ + async getTownsByState(idState: number, stateName: string): Promise { + return this.datasource.getTownsByState(idState, stateName); + } + + /** + * Retrieves a town by its ID. + * @param idTown - The ID of the town. + * @returns A promise that resolves to a Town object. + */ + async getTown(idTown: number): Promise { + return this.datasource.getTown(idTown); + } + + /** + * Updates an existing town. + * @param form - The town data to update. + * @returns A promise that resolves when the town is updated. + */ + async updateTown(form: Town): Promise { + return this.datasource.updateTown(form); + } +} diff --git a/web/src/domain/model/AdminModel.ts b/web/src/domain/model/AdminModel.ts new file mode 100644 index 00000000..6cea6275 --- /dev/null +++ b/web/src/domain/model/AdminModel.ts @@ -0,0 +1,17 @@ +/** + * Interface representing an admin model. + */ +export interface AdminModel { + /** Email of the admin */ + email: string; + /** First name of the admin */ + name: string; + /** Last name of the admin */ + lastName: string; + /** Optional role of the admin */ + role?: string; + /** Optional unique identifier for the town */ + idTown?: number; + /** Status of the admin */ + status: string; +} \ No newline at end of file diff --git a/web/src/domain/model/CategoryModel.ts b/web/src/domain/model/CategoryModel.ts new file mode 100644 index 00000000..3e780c91 --- /dev/null +++ b/web/src/domain/model/CategoryModel.ts @@ -0,0 +1,21 @@ +/** + * Interface representing a category model. + */ +export interface CategoryModel { + /** Unique identifier for the category */ + idCategory: number; + /** Name of the category */ + name: string; +} + +/** + * Interface representing a category model with language information. + */ +export interface CategoryModelLan { + /** Unique identifier for the category */ + idCategory: number; + /** Language of the category name */ + language: string; + /** Name of the category */ + name: string; +} \ No newline at end of file diff --git a/web/src/domain/model/LoggedInUserModel.ts b/web/src/domain/model/LoggedInUserModel.ts new file mode 100644 index 00000000..0db9d5a2 --- /dev/null +++ b/web/src/domain/model/LoggedInUserModel.ts @@ -0,0 +1,24 @@ +/** + * Interface representing a logged-in user model. + */ +export interface LoggedInUserModel { + /** + * The email address of the logged-in user. + */ + email: string; + + /** + * The name of the logged-in user. + */ + name: string; + + /** + * The role of the logged-in user (e.g., admin, user). + */ + role: string; + + /** + * The authentication token for the logged-in user. + */ + token: string; +} \ No newline at end of file diff --git a/web/src/domain/model/POIModel.ts b/web/src/domain/model/POIModel.ts new file mode 100644 index 00000000..72d14080 --- /dev/null +++ b/web/src/domain/model/POIModel.ts @@ -0,0 +1,38 @@ +import { PointOfInterest } from "../../data/datasource/api/entities/poi"; + +/** + * Interface representing a Point of Interest (POI) model. + */ +export interface POIModel { + /** Unique identifier for the point of interest */ + idPoint: number; + /** Unique identifier for the place */ + idPlace: number; + /** Name of the point of interest */ + name: string; + /** Image name associated with the point of interest */ + imageName: string; + /** Content description of the point of interest */ + content: string; + /** Directions to the point of interest */ + directions: string; +} + +/** + * Converts a POIModel to a PointOfInterest entity. + * @param model - The POIModel to convert. + * @returns The converted PointOfInterest entity. + */ +export const POIModelToEntity = (model: POIModel): PointOfInterest => { + const poi: PointOfInterest = { + idPoint: model.idPoint, + idPlace: model.idPlace, + name: model.name, + image: model.imageName, + contentES: model.content, + contentEN: model.content, + directionsES: model.directions, + directionsEN: model.directions, + }; + return poi; +}; diff --git a/web/src/domain/model/PlaceModel.ts b/web/src/domain/model/PlaceModel.ts new file mode 100644 index 00000000..e9d83406 --- /dev/null +++ b/web/src/domain/model/PlaceModel.ts @@ -0,0 +1,77 @@ +import { AvailableDays, Place } from "../../data/datasource/api/entities/place"; +import { CategoryModelLan } from "./CategoryModel"; + +/** + * Interface representing a place model. + */ +export interface PlaceModel { + /** Unique identifier for the town */ + idTown: number; + /** Unique identifier for the place */ + idPlace: number; + /** Availability of the place */ + available: string; + /** Description of the place */ + description: string; + /** Latitude coordinate of the place */ + latitude: number; + /** Longitude coordinate of the place */ + longitude: number; + /** Image name associated with the place */ + imageName: string; + /** Name of the place */ + name: string; + /** Categories associated with the place */ + categories: CategoryModelLan[]; + /** Opening time of the place */ + openAt: number; + /** Closing time of the place */ + closeAt: number; + /** Optional start date for the place */ + startDate?: Date; + /** Optional end date for the place */ + endDate?: Date; + /** Address of the place */ + address: string; +} + +/** + * Converts a PlaceModel to a Place entity. + * @param model - The PlaceModel to convert. + * @returns The converted Place entity. + */ +export const placeModelToEntity = (model: PlaceModel): Place => { + let availableDays = AvailableDays.WEEKEND; + switch (model.available) { + case AvailableDays.ALL_DAYS: + availableDays = AvailableDays.ALL_DAYS; + break; + case AvailableDays.CUSTOM: + availableDays = AvailableDays.CUSTOM; + break; + case AvailableDays.WEEKDAYS: + availableDays = AvailableDays.WEEKDAYS; + break; + default: + availableDays = AvailableDays.WEEKEND; + break; + } + + const place: Place = { + idTown: model.idTown, + idPlace: model.idPlace, + available: availableDays, + latitude: model.latitude, + longitude: model.longitude, + descriptions: [model.description], + imagesList: [model.imageName], + name: model.name, + categoriesId: model.categories.map((category) => category.idCategory), + openAt: model.openAt, + closeAt: model.closeAt, + startDate: model.startDate, + endDate: model.endDate, + address: model.address, + }; + return place; +}; diff --git a/web/src/domain/model/StateModel.ts b/web/src/domain/model/StateModel.ts new file mode 100644 index 00000000..fc76339a --- /dev/null +++ b/web/src/domain/model/StateModel.ts @@ -0,0 +1,11 @@ +/** + * Interface representing a state model. + */ +export interface StateModel { + /** Unique identifier for the state */ + stateId: number; + /** Name of the state */ + name: string; + /** URL of the image representing the state */ + imageURL: string; +} diff --git a/web/src/domain/model/TownModel.ts b/web/src/domain/model/TownModel.ts new file mode 100644 index 00000000..5f5cd4b5 --- /dev/null +++ b/web/src/domain/model/TownModel.ts @@ -0,0 +1,33 @@ +/** + * Interface representing a traditional town model. + */ +export interface TownModelTrad { + /** Unique identifier for the town */ + townId: number; + /** Name of the town */ + name: string; + /** Image name associated with the town */ + imageName: string; + /** Description of the town */ + description: string; + /** Unique identifier for the state */ + stateId: number; +} + +/** + * Interface representing a town model with multilingual descriptions. + */ +export interface TownModel { + /** Unique identifier for the town */ + townId: number; + /** Name of the town */ + name: string; + /** English description of the town */ + descriptionEN: string; + /** Spanish description of the town */ + descriptionES: string; + /** Image name associated with the town */ + imageName: string; + /** Unique identifier for the state */ + stateId: number; +} \ No newline at end of file diff --git a/web/src/domain/repository/admin_repository.ts b/web/src/domain/repository/admin_repository.ts new file mode 100644 index 00000000..3c2d9144 --- /dev/null +++ b/web/src/domain/repository/admin_repository.ts @@ -0,0 +1,58 @@ +import { + Admin, + AdminFormValues, +} from "../../data/datasource/api/entities/admin_form_values"; +import { ResetPasswordValues } from "../../data/datasource/api/entities/reset_password_values"; + +/** + * Interface representing a repository for handling admin-related operations. + */ +export interface AdminRepositoryInf { + /** + * Registers a new admin. + * @param form - The admin data to register. + * @returns A promise that resolves when the admin is registered. + */ + registerAdmin(form: AdminFormValues): Promise ; + + /** + * Retrieves admin information based on a token. + * @param token - The token to authenticate the request. + * @returns A promise that resolves to an Admin object. + */ + getAdminInfo(token: string): Promise