diff --git a/angular/RestClient/package-lock.json b/angular/RestClient/package-lock.json index 1ab79b2b39ab9d43633bab9b1dff2e461d3d40ff..a5d201bf11869266cc967b0e328660d5d8870bc7 100644 --- a/angular/RestClient/package-lock.json +++ b/angular/RestClient/package-lock.json @@ -37,15 +37,31 @@ "@types/express": "^4.17.17", "@types/jasmine": "~5.1.0", "@types/node": "^18.18.0", + "autoprefixer": "^10.4.20", "jasmine-core": "~5.2.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", "typescript": "~5.5.2" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -204,6 +220,35 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss": { + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -5124,6 +5169,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -5151,6 +5203,13 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5636,6 +5695,16 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001676", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", @@ -6530,6 +6599,20 @@ "dev": true, "license": "MIT" }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -8965,6 +9048,16 @@ } } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -9811,6 +9904,18 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -10237,6 +10342,16 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -10738,6 +10853,16 @@ "node": ">=6" } }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/piscina": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", @@ -10765,9 +10890,9 @@ } }, "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "funding": [ { "type": "opencollective", @@ -10785,13 +10910,100 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/postcss-loader": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", @@ -10893,6 +11105,32 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", @@ -11059,6 +11297,26 @@ "node": ">= 0.8" } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -12344,6 +12602,86 @@ "node": ">=6" } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12379,6 +12717,44 @@ "node": ">=0.10" } }, + "node_modules/tailwindcss": { + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -12570,6 +12946,29 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thingies": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", @@ -12651,6 +13050,13 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -13450,35 +13856,6 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/vite/node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -14068,6 +14445,19 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/angular/RestClient/package.json b/angular/RestClient/package.json index e6e13700b4190bd940226eb510d491ceda4997dc..262eacd1144f0eaab113dda4aad24eedab9ff958 100644 --- a/angular/RestClient/package.json +++ b/angular/RestClient/package.json @@ -40,12 +40,15 @@ "@types/express": "^4.17.17", "@types/jasmine": "~5.1.0", "@types/node": "^18.18.0", + "autoprefixer": "^10.4.20", "jasmine-core": "~5.2.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", "typescript": "~5.5.2" } } diff --git a/angular/RestClient/public/search.svg b/angular/RestClient/public/search.svg new file mode 100644 index 0000000000000000000000000000000000000000..5833a246d21d7f3442153559710b642e3fdc179d --- /dev/null +++ b/angular/RestClient/public/search.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px" fill-rule="nonzero"><g fill="#ffffff" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M21,3c-9.39844,0 -17,7.60156 -17,17c0,9.39844 7.60156,17 17,17c3.35547,0 6.46094,-0.98437 9.09375,-2.65625l12.28125,12.28125l4.25,-4.25l-12.125,-12.09375c2.17969,-2.85937 3.5,-6.40234 3.5,-10.28125c0,-9.39844 -7.60156,-17 -17,-17zM21,7c7.19922,0 13,5.80078 13,13c0,7.19922 -5.80078,13 -13,13c-7.19922,0 -13,-5.80078 -13,-13c0,-7.19922 5.80078,-13 13,-13z"></path></g></g></svg> \ No newline at end of file diff --git a/angular/RestClient/src/app/app.component.html b/angular/RestClient/src/app/app.component.html index 086c08469b743ad84e40ff603386f80cb56d4e88..94ead7dd6b3d1d18c77eb5ad41ff2a32f4a097ad 100644 --- a/angular/RestClient/src/app/app.component.html +++ b/angular/RestClient/src/app/app.component.html @@ -1,4 +1,4 @@ <div class="container"> - <h3>Ejemplo angular. Gestión de reservas</h3> + <app-navigation /> <router-outlet></router-outlet> </div> diff --git a/angular/RestClient/src/app/app.component.ts b/angular/RestClient/src/app/app.component.ts index 0d3b21a781b1019a1f82594eb2d3e0b6cbcce844..55843458c953cc2375c625dfc4c5f6fffd331059 100644 --- a/angular/RestClient/src/app/app.component.ts +++ b/angular/RestClient/src/app/app.component.ts @@ -1,12 +1,13 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import { NavigationComponent } from './navigation/navigation.component'; @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet], + imports: [RouterOutlet, NavigationComponent], templateUrl: './app.component.html', - styleUrl: './app.component.css' + styleUrl: './app.component.css', }) export class AppComponent { title = 'RestClient'; diff --git a/angular/RestClient/src/app/app.config.ts b/angular/RestClient/src/app/app.config.ts index 90d16a2680995da9bfe69cc6236811df872c23ad..1f668ea1741efbdb605f6d418a9a93f53f1327fa 100644 --- a/angular/RestClient/src/app/app.config.ts +++ b/angular/RestClient/src/app/app.config.ts @@ -1,16 +1,11 @@ -import { - ApplicationConfig, - importProvidersFrom, - provideZoneChangeDetection, -} from '@angular/core'; +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideHttpClient, withFetch } from '@angular/common/http'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { ReactiveFormsModule } from '@angular/forms'; // Added import for ReactiveFormsModule import { provideNativeDateAdapter } from '@angular/material/core'; -import { FormsModule } from '@angular/forms'; -import { CommonEngine } from '@angular/ssr'; +import { provideClientHydration } from '@angular/platform-browser'; export const appConfig: ApplicationConfig = { providers: [ @@ -20,6 +15,6 @@ export const appConfig: ApplicationConfig = { provideClientHydration(), provideHttpClient(withFetch()), provideAnimationsAsync(), - ReactiveFormsModule - ] + ReactiveFormsModule, + ], }; diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index 2dd95b52261263abe4e4110f1025bec2b5d36e4c..58c8bafb892d5d8be0368bfa18b6cea01d1ddb15 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -1,6 +1,6 @@ import { Routes } from '@angular/router'; import { HotelListComponent } from './hotel-list/hotel-list.component'; -import { BookingComponent } from './booking/booking.component'; +import { BookingComponent } from './booking/booking.component'; import { BookingListComponent } from './booking-list/booking-list.component'; import { HotelRegisterComponent } from './hotel-register/hotel-register.component'; import { MainPageComponent } from './main-page/main-page.component'; @@ -26,13 +26,13 @@ export const routes: Routes = [ path: 'hotels/:id', component: HotelRegisterComponent, }, - { - path: '**', - redirectTo: '', - pathMatch: 'full', - }, { path: 'booking', // Añade la ruta para el componente de reservas component: BookingComponent, - } -] \ No newline at end of file + }, + { + path: '**', + redirectTo: '', + pathMatch: 'full', + }, +]; diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.css b/angular/RestClient/src/app/booking-list/booking-list.component.css index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fcbb63ff2da3990e7eb2bffbfedcd84cadac8004 100644 --- a/angular/RestClient/src/app/booking-list/booking-list.component.css +++ b/angular/RestClient/src/app/booking-list/booking-list.component.css @@ -0,0 +1,8 @@ +.container { + max-width: 1000px; + margin-top: 2rem; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #f9f9f9; +} diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.html b/angular/RestClient/src/app/booking-list/booking-list.component.html index 653fb3a73614955a1d731766f9b0aaed7cad5665..a3812b6c4b078ab5be691005674ff267fbb6a10a 100644 --- a/angular/RestClient/src/app/booking-list/booking-list.component.html +++ b/angular/RestClient/src/app/booking-list/booking-list.component.html @@ -1,51 +1,82 @@ -<div> - <mat-form-field> - <mat-label>Enter a date range</mat-label> - <mat-date-range-input [rangePicker]="picker"> - <input - matStartDate - placeholder="Start date" - (dateInput)="updateStart($event)" - (dateChange)="updateStart($event)" - /> - <input - matEndDate - placeholder="End date" - (dateInput)="updateEnd($event)" - (dateChange)="updateEnd($event)" - /> - </mat-date-range-input> - <mat-hint>MM/DD/YYYY – MM/DD/YYYY</mat-hint> - <mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle> - <mat-date-range-picker #picker></mat-date-range-picker> - </mat-form-field> - <mat-form-field> - <mat-label>Hotel</mat-label> - <mat-select [(value)]="hotelSelected"> - @for (hotel of hotels; track hotel.id) { - <mat-option [value]="hotel.id">{{ hotel.name }}</mat-option> +<div class="container"> + <mat-card> + <mat-card-title class="flex text-center p-4"> + <strong class="text-5xl">Registro de Hotel</strong> + </mat-card-title> + + <mat-card-content> + <div class="form-group text-xl flex justify-center gap-20"> + <mat-form-field> + <mat-label class="text-2xl">Enter a date range</mat-label> + <mat-date-range-input [rangePicker]="picker"> + <input + matStartDate + placeholder="Start date" + (dateInput)="updateStart($event)" + (dateChange)="updateStart($event)" + /> + <input + matEndDate + placeholder="End date" + (dateInput)="updateEnd($event)" + (dateChange)="updateEnd($event)" + /> + </mat-date-range-input> + <mat-datepicker-toggle + matIconSuffix + [for]="picker" + ></mat-datepicker-toggle> + <mat-date-range-picker #picker></mat-date-range-picker> + </mat-form-field> + <mat-form-field> + <mat-label class="text-2xl">Hotel</mat-label> + <mat-select [(value)]="hotelSelected" class="text-2xl"> + @for (hotel of hotels; track hotel.id) { + <mat-option [value]="hotel" class="text-3xl">{{ + hotel.name + }}</mat-option> + } + </mat-select> + </mat-form-field> + <button + [disabled]="!this.start || !this.end || !this.hotelSelected" + mat-raised-button + class="bg-blue-500 rounded-full p-2" + (click)="search()" + > + <img class="w-3/4" src="/search.svg" /> + </button> + <mat-form-field> + <mat-label>Filter by Room Type</mat-label> + <mat-select + [(value)]="roomTypeSelected" + (selectionChange)="updateRooms()" + > + @for (type of roomTypes; track type) { + <mat-option [value]="type">{{ type }}</mat-option> + } + </mat-select> + </mat-form-field> + </div> + <!-- Lista de Habitaciones --> + @if (trateRooms.length > 0) { + <div class="grid gap-4 text-lg mb-8"> + <h2 class="text-2xl font-semibold mb-4">Habitaciones Disponibles</h2> + <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"> + @for(room of trateRooms; track room.id) { + <button + mat-raised-button + color="accent" + class="w-full text-center py-3 rounded-lg shadow-md hover:shadow-lg text-2xl" + (click)="bookingRoom(room.id)" + > + <strong>Habitación {{ room.roomNumber }}</strong> - + <span class="italic">{{ room.type }}</span> (#{{ $index + 1 }}) + </button> + } + </div> + </div> } - </mat-select> - </mat-form-field> - <mat-form-field> - <mat-label>Room Type</mat-label> - <mat-select [(value)]="roomTypeSelected" (selectionChange)="updateRooms()"> - @for (type of roomTypes; track type) { - <mat-option [value]="type">{{ type }}</mat-option> - } - </mat-select> - </mat-form-field> - <button - [disabled]="!this.start || !this.end || this.hotelSelected == -1" - mat-raised-button - color="primary" - (click)="search()" - > - Search - </button> - @for (room of trateRooms; track $index) { - <button (click)="bookingRoom(room.id)"> - {{ room.id }} {{ room.type }} {{ room.roomNumber }} - </button> - } + </mat-card-content> + </mat-card> </div> diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.ts b/angular/RestClient/src/app/booking-list/booking-list.component.ts index 41d5976b734d93abfa3d2e0457af80f6e2c09c5b..27e093fead7238aea2b2b5ea9d241b7dc8a9549f 100644 --- a/angular/RestClient/src/app/booking-list/booking-list.component.ts +++ b/angular/RestClient/src/app/booking-list/booking-list.component.ts @@ -6,10 +6,11 @@ import { } from '@angular/material/datepicker'; import { FormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; -import { MatSelectChange, MatSelectModule } from '@angular/material/select'; +import { MatSelectModule } from '@angular/material/select'; import { Hotel, Room, RoomType, roomTypeArray } from '../../types'; import { ClienteApiRestService } from '../shared/cliente-api-rest.service'; import { Router } from '@angular/router'; +import { MatCard, MatCardModule } from '@angular/material/card'; type SelectableRoomType = 'All' | RoomType; const selectableRoomTypeArray: SelectableRoomType[] = ['All', ...roomTypeArray]; @@ -20,6 +21,7 @@ const selectableRoomTypeArray: SelectableRoomType[] = ['All', ...roomTypeArray]; imports: [ MatFormFieldModule, MatDatepickerModule, + MatCardModule, MatFormFieldModule, MatSelectModule, MatInputModule, @@ -32,7 +34,7 @@ export class BookingListComponent { start?: Date; end?: Date; hotels!: Hotel[]; - hotelSelected: number = -1; + hotelSelected?: Hotel; roomTypeSelected?: SelectableRoomType; roomTypes = selectableRoomTypeArray; rooms: Room[] = []; @@ -47,7 +49,7 @@ export class BookingListComponent { getHotels() { this.client.getAllHotels().subscribe({ next: (resp) => { - if (resp.body != null) this.hotels = [...resp.body]; + if (resp != null) this.hotels = [...resp]; }, error(err) { console.log('Error al traer la lista: ' + err.message); @@ -66,7 +68,11 @@ export class BookingListComponent { search() { this.client - .getRoomsAvailableInDateRange(this.hotelSelected, this.start!, this.end!) + .getRoomsAvailableInDateRange( + this.hotelSelected!.id, + this.start!, + this.end! + ) .subscribe({ next: (resp) => { this.rooms = resp; @@ -83,6 +89,6 @@ export class BookingListComponent { } bookingRoom(roomId: number) { - this.router.navigateByUrl(`/booking?room=${roomId}`); + this.router.navigate(['/booking'], { queryParams: { roomId } }); } } diff --git a/angular/RestClient/src/app/booking/booking.component.html b/angular/RestClient/src/app/booking/booking.component.html index fba44008cc32e506e7ff27ca1d3ad0051b3c068a..fd958650cb24eac92fe0bf1b969561bbf117a95f 100644 --- a/angular/RestClient/src/app/booking/booking.component.html +++ b/angular/RestClient/src/app/booking/booking.component.html @@ -1,36 +1,46 @@ <div class="container"> - <h2>Crear Reserva</h2> - <form [formGroup]="bookingForm" (ngSubmit)="submitBooking()"> - <div class="form-group"> - <label for="userId">ID del Usuario:</label> - <input type="number" id="userId" formControlName="userId" class="form-control" /> - </div> - <div class="form-group"> - <label for="hotelId">ID del Hotel:</label> - <input type="number" id="hotelId" formControlName="hotelId" class="form-control" /> - </div> - - <div class="form-group"> - <label for="roomType">Tipo de Habitación:</label> - <select id="roomType" formControlName="roomType" class="form-control"> - <option value="">Seleccione</option> - <option value="single">Individual</option> - <option value="double">Doble</option> - <option value="suite">Suite</option> - </select> - </div> - - <div class="form-group"> - <label for="startDate">Fecha de Inicio:</label> - <input type="date" id="startDate" formControlName="startDate" class="form-control" /> - </div> - - <div class="form-group"> - <label for="endDate">Fecha de Fin:</label> - <input type="date" id="endDate" formControlName="endDate" class="form-control" /> - </div> - - <button type="submit" class="btn btn-primary">Reservar</button> - </form> - </div> - \ No newline at end of file + <h2>Crear Reserva</h2> + <form [formGroup]="bookingForm" (ngSubmit)="submitBooking()"> + <div class="form-group"> + <label for="userId">Usuario:</label> + <input + type="number" + id="userId" + formControlName="userId" + class="form-control" + /> + </div> + + <div class="form-group"> + <label for="roomType">Tipo de Habitación:</label> + <select id="roomType" formControlName="roomType" class="form-control"> + <option value="">Seleccione</option> + <option value="single">Individual</option> + <option value="double">Doble</option> + <option value="suite">Suite</option> + </select> + </div> + + <div class="form-group"> + <label for="startDate">Fecha de Inicio:</label> + <input + type="date" + id="startDate" + formControlName="startDate" + class="form-control" + /> + </div> + + <div class="form-group"> + <label for="endDate">Fecha de Fin:</label> + <input + type="date" + id="endDate" + formControlName="endDate" + class="form-control" + /> + </div> + + <button type="submit" class="btn btn-primary">Reservar</button> + </form> +</div> diff --git a/angular/RestClient/src/app/booking/booking.component.ts b/angular/RestClient/src/app/booking/booking.component.ts index 9636e65609448ce2df6cf698da2186627c937722..c9288039b0567f1cb640b66a139f7b8fc18212c7 100644 --- a/angular/RestClient/src/app/booking/booking.component.ts +++ b/angular/RestClient/src/app/booking/booking.component.ts @@ -13,6 +13,7 @@ interface BookingRequest { endDate: string; // Fecha de fin de la reserva// Asegúrate de ajustar la ruta } import { BookingService } from '../shared/booking.service'; // Asegúrate de que el servicio exista +import { ActivatedRoute } from '@angular/router'; @Component({ standalone: true, @@ -23,8 +24,13 @@ import { BookingService } from '../shared/booking.service'; // Asegúrate de que }) export class BookingComponent implements OnInit { bookingForm: FormGroup; + roomId: number = 0; - constructor(private fb: FormBuilder, private bookingService: BookingService) { + constructor( + private route: ActivatedRoute, + private fb: FormBuilder, + private bookingService: BookingService + ) { // Inicialización del formulario con validaciones this.bookingForm = this.fb.group({ userId: ['', Validators.required], @@ -35,7 +41,11 @@ export class BookingComponent implements OnInit { }); } - ngOnInit(): void {} + ngOnInit() { + this.route.queryParams.subscribe((params) => { + this.roomId = params['roomId']; + }); + } submitBooking() { if (this.bookingForm.valid) { diff --git a/angular/RestClient/src/app/hotel-list/hotel-list.component.css b/angular/RestClient/src/app/hotel-list/hotel-list.component.css index 9f12f813c2cd81682e684b77df1e2510e33ca0cc..fcbb63ff2da3990e7eb2bffbfedcd84cadac8004 100644 --- a/angular/RestClient/src/app/hotel-list/hotel-list.component.css +++ b/angular/RestClient/src/app/hotel-list/hotel-list.component.css @@ -1,7 +1,8 @@ -.header-text { - font-size: large; -} - -.body-text { - font-size: small; +.container { + max-width: 1000px; + margin-top: 2rem; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #f9f9f9; } diff --git a/angular/RestClient/src/app/hotel-list/hotel-list.component.html b/angular/RestClient/src/app/hotel-list/hotel-list.component.html index 816b68c10fce61eda089cc524b00b05a88b0f8cb..a97254ba286fcb168c472d0f717d7bff62409a50 100644 --- a/angular/RestClient/src/app/hotel-list/hotel-list.component.html +++ b/angular/RestClient/src/app/hotel-list/hotel-list.component.html @@ -1,24 +1,28 @@ <div class="container"> - <h2 style="text-align: center">Hotel List</h2> + <h2 class="text-center text-5xl font-bold mb-4">Hotel List</h2> <mat-accordion> - <mat-expansion-panel disabled=""> - <mat-expansion-panel-header class="header-text"> - <mat-panel-title>HOTEL</mat-panel-title> - <mat-panel-description>Location</mat-panel-description> + <mat-expansion-panel disabled class="cursor-default"> + <mat-expansion-panel-header> + <mat-panel-title class="text-3xl font-bold">Hotel</mat-panel-title> + <mat-panel-description class="text-3xl font-bold" + >Location</mat-panel-description + > </mat-expansion-panel-header> </mat-expansion-panel> @for(hotel of hotels; track hotel.id) { - <mat-expansion-panel expanded="true"> - <mat-expansion-panel-header class="header-text"> - <mat-panel-title> {{ hotel.id }}. {{ hotel.name }} </mat-panel-title> - <mat-panel-description> + <mat-expansion-panel> + <mat-expansion-panel-header> + <mat-panel-title class="text-3xl"> + {{ $index + 1 }}. {{ hotel.name }} + </mat-panel-title> + <mat-panel-description class="text-3xl"> {{ hotel.address.streetKind }} {{ hotel.address.streetName }} No. {{ hotel.address.number }}, {{ hotel.address.postCode }} {{ hotel.address.otherInfo }} </mat-panel-description> </mat-expansion-panel-header> - <div style="text-align: end; margin-bottom: 1rem"> + <div class="text-end mb-4"> <button mat-raised-button (click)="goToHotelDetails(hotel.id)" @@ -34,6 +38,7 @@ mat-raised-button (click)="deleteHotel(hotel.id)" style=" + margin-left: 2rem; font-size: medium; background-color: rgb(223, 36, 36); color: rgb(250, 250, 250); @@ -44,26 +49,26 @@ </div> <table mat-table [dataSource]="hotel.rooms" class="mat-elevation-z8"> <ng-container matColumnDef="roomNumber"> - <th class="header-text" mat-header-cell *matHeaderCellDef> + <th class="text-3xl" mat-header-cell *matHeaderCellDef> Room Number </th> - <td class="body-text" mat-cell *matCellDef="let room"> + <td class="text-2xl" mat-cell *matCellDef="let room"> {{ room.roomNumber }} </td> </ng-container> <ng-container matColumnDef="type"> - <th class="header-text" mat-header-cell *matHeaderCellDef>Type</th> - <td class="body-text" ce mat-cell *matCellDef="let room"> + <th class="text-3xl" mat-header-cell *matHeaderCellDef>Type</th> + <td class="text-2xl" ce mat-cell *matCellDef="let room"> {{ room.type }} </td> </ng-container> <ng-container matColumnDef="available"> - <th class="header-text" mat-header-cell *matHeaderCellDef> + <th class="text-3xl text-center" mat-header-cell *matHeaderCellDef> Available </th> - <td class="body-text" mat-cell *matCellDef="let room"> + <td class="text-2xl" mat-cell *matCellDef="let room"> <mat-slide-toggle [checked]="room.available" (change)=" diff --git a/angular/RestClient/src/app/hotel-register/hotel-register.component.css b/angular/RestClient/src/app/hotel-register/hotel-register.component.css index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..79b4834ee543b62f19df182154eeb62fa0911db1 100644 --- a/angular/RestClient/src/app/hotel-register/hotel-register.component.css +++ b/angular/RestClient/src/app/hotel-register/hotel-register.component.css @@ -0,0 +1,21 @@ +.container { + max-width: 600px; + margin-top: 2rem; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #f9f9f9; +} + +h2 { + text-align: center; + margin-bottom: 20px; +} + +.form-group { + margin-bottom: 15px; +} + +label { + font-weight: bold; +} diff --git a/angular/RestClient/src/app/hotel-register/hotel-register.component.html b/angular/RestClient/src/app/hotel-register/hotel-register.component.html index 57abb5148e14642a64d31c1780d04b26082f6d4f..490aa3aacc1d222405ff173335b79b1aa6b844e2 100644 --- a/angular/RestClient/src/app/hotel-register/hotel-register.component.html +++ b/angular/RestClient/src/app/hotel-register/hotel-register.component.html @@ -1,47 +1,47 @@ <div class="container"> <form [formGroup]="hotelForm"> <mat-card> - <mat-card-title class="fs-1 d-flex justify-content-center mt-5" - ><strong>Registro de Hotel</strong></mat-card-title - > + <mat-card-title class="flex text-center p-4"> + <strong class="text-5xl">Registro de Hotel</strong> + </mat-card-title> <mat-card-content> <div class="form-group"> - <label for="name" class="display-2">Nombre del Hotel</label> + <label for="name" class="text-3xl">Nombre del Hotel</label> <input id="name" - class="form-control fs-3" + class="form-control" formControlName="name" placeholder="Nombre del hotel" /> </div> - <div class="form-group mt-3"> - <label class="fs-2">Dirección</label> + <div class="form-group text-3xl"> + <label class="">Dirección</label> <div formGroupName="address"> <input - class="form-control mb-2 fs-3" + class="form-control mb-2" formControlName="streetKind" placeholder="Tipo de calle" /> <input - class="form-control mb-2 fs-3" + class="form-control mb-2" formControlName="streetName" placeholder="Nombre de la calle" /> <input - class="form-control mb-2 fs-3" + class="form-control mb-2" formControlName="number" type="number" min="1" placeholder="Número" /> <input - class="form-control mb-2 fs-3" + class="form-control mb-2" formControlName="postCode" placeholder="Código Postal" /> <input - class="form-control mb-2 fs-3" + class="form-control mb-2" formControlName="otherInfo" placeholder="Otra información (opcional)" /> @@ -50,15 +50,15 @@ <!-- Lista de habitaciones --> <div formArrayName="rooms"> - <div class="d-flex gap-4 align-items-center mb-3"> - <label class="fs-2">Habitaciones</label> + <div class="flex gap-4 items-center mb-3"> + <label class="text-3xl">Habitaciones</label> <button - class="btn btn-primary rounded-circle" + class="btn btn-primary rounded-full" (click)="addRoom()" [hidden]="editMode" [disabled]="editMode" > - <strong class="fs-2">+</strong> + <strong class="text-3xl">+</strong> </button> </div> @@ -67,10 +67,8 @@ [formGroupName]="i" class="form-row row align-items-center mb-3" > - <div - class="col-md-12 d-flex justify-content-between align-items-center mb-3" - > - <span class="d-flex gap-4 align-items-center pa fs-3"> + <div class="col-md-12 flex justify-between align-items-center mb-3"> + <span class="flex gap-4 items-center pa fs-3"> <label>Habitación {{ i + 1 }}</label> <!-- Disponibilidad de habitación --> <mat-slide-toggle formControlName="available" @@ -80,57 +78,56 @@ <button class="btn btn-danger" (click)="removeRoom(i)" - [disabled]="rooms.length <= 1" + [disabled]="editMode || rooms.length <= 1" [hidden]="editMode" - [disabled]="editMode" > Eliminar </button> </div> <!-- Número de habitación --> - <div class="col-md-6"> - <mat-form-field appearance="fill" class="w-100"> - <mat-label class="fs-3">Número de habitación</mat-label> + <mat-form-field appearance="fill" class="w-full"> + <mat-label class="text-2xl">Número de habitación</mat-label> <input matInput formControlName="roomNumber" placeholder="104A" - class="fs-3" + class="text-2xl" /> </mat-form-field> </div> <!-- Tipo de habitación --> <div class="col-md-6"> - <mat-form-field appearance="fill" class="w-100"> - <mat-label class="fs-3">Tipo de habitación</mat-label> - <mat-select formControlName="type" class="fs-3"> - <mat-option class="fs-3" value="SINGLE">Single</mat-option> - <mat-option class="fs-3" value="DOUBLE">Double</mat-option> - <mat-option class="fs-3" value="SUITE">Suite</mat-option> + <mat-form-field appearance="fill" class="w-full"> + <mat-label class="text-2xl">Tipo de habitación</mat-label> + <mat-select formControlName="type"> + <mat-option class="text-2xl" value="SINGLE" + >Single</mat-option + > + <mat-option class="text-2xl" value="DOUBLE" + >Double</mat-option + > + <mat-option class="text-2xl" value="SUITE">Suite</mat-option> </mat-select> </mat-form-field> </div> </div> </div> </mat-card-content> - - <mat-card-actions - [hidden]="editMode" - class="d-flex justify-content-center" - > + @if (!editMode) { + <mat-card-actions class="flex justify-center mb-5"> <button type="submit" - class="btn btn-success" + class="btn btn-success text-5xl" (click)="onSubmit()" - [disabled]="editMode || !hotelForm.valid" - [hidden]="editMode" + [disabled]="!hotelForm.valid" > - <h4>Guardar Hotel</h4> + Guardar Hotel </button> </mat-card-actions> + } </mat-card> </form> </div> diff --git a/angular/RestClient/src/app/navigation/navigation.component.css b/angular/RestClient/src/app/navigation/navigation.component.css index 6180318f967d8214510bc0b3c6201221412b25d2..ac9b23bf96a577a2cda9f2219491001f721aeea4 100644 --- a/angular/RestClient/src/app/navigation/navigation.component.css +++ b/angular/RestClient/src/app/navigation/navigation.component.css @@ -1,29 +1,44 @@ nav { - background-color: #333; - color: white; - padding: 1em; + background-color: #333; + color: white; + padding: 1em; +} + +ul { + list-style: none; + padding: 0; + display: flex; +} + +li { + margin-right: 20px; +} + +a, +a:visited { + color: white; + text-decoration: none; + transform: scale(1); + transition: transform 0.3s ease; +} + +a:hover { + font-weight: bold; + text-decoration: underline; + color: yellow; + transition: transform 0.3s ease; + transform: scale(2); +} + +.active { + font-weight: bold; +} + +@keyframes escalar { + 0% { + transform: scale(1); } - - ul { - list-style: none; - padding: 0; - display: flex; + 100% { + transform: scale(2); } - - li { - margin-right: 20px; - } - - a { - color: white; - text-decoration: none; - } - - a:hover { - text-decoration: underline; - } - - .active { - font-weight: bold; - } - \ No newline at end of file +} diff --git a/angular/RestClient/src/app/navigation/navigation.component.html b/angular/RestClient/src/app/navigation/navigation.component.html index 28eb7b3afd34eff566b5d124a6f96cf5bf9187d4..e2433bed901858189d70ef6d639450def8f36fe4 100644 --- a/angular/RestClient/src/app/navigation/navigation.component.html +++ b/angular/RestClient/src/app/navigation/navigation.component.html @@ -1,7 +1,12 @@ <nav> - <ul> - <li><a routerLink="/hotels" routerLinkActive="Hoteles">Home</a></li> - <li><a routerLink="/about" routerLinkActive="active">About</a></li> - </ul> - </nav> - \ No newline at end of file + <ul> + <li><a class="btn" [routerLink]="['/']">Home</a></li> + <li> + <a class="btn" [routerLink]="['/hotels', 'new']">Registrar Hotel</a> + </li> + <li><a class="btn" [routerLink]="['/hotels']">Hoteles</a></li> + <li> + <a class="btn" [routerLink]="['/booking', 'search']">Nueva Reserva</a> + </li> + </ul> +</nav> diff --git a/angular/RestClient/src/app/navigation/navigation.component.ts b/angular/RestClient/src/app/navigation/navigation.component.ts index 8ca86e68eb7d801dfb19fb5a0bba6ab78c9b2dae..ccdab77b49379e3ed27abd65ada67e693882939a 100644 --- a/angular/RestClient/src/app/navigation/navigation.component.ts +++ b/angular/RestClient/src/app/navigation/navigation.component.ts @@ -1,12 +1,10 @@ import { Component } from '@angular/core'; - +import { Router, RouterModule } from '@angular/router'; @Component({ selector: 'app-navigation', standalone: true, - imports: [], + imports: [RouterModule], templateUrl: './navigation.component.html', - styleUrl: './navigation.component.css' + styleUrl: './navigation.component.css', }) -export class NavigationComponent { - -} +export class NavigationComponent {} diff --git a/angular/RestClient/src/app/shared/cliente-api-rest.service.ts b/angular/RestClient/src/app/shared/cliente-api-rest.service.ts index 901197fd57be961b0d2546a15688fea828f02631..2ef2d202cba1e4b65a219472c37b5335963cfdc1 100644 --- a/angular/RestClient/src/app/shared/cliente-api-rest.service.ts +++ b/angular/RestClient/src/app/shared/cliente-api-rest.service.ts @@ -1,6 +1,5 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; import { Hotel, Booking, Room } from '../../types'; import { Observable } from 'rxjs'; import { User } from '../../types'; @@ -53,7 +52,7 @@ export class ClienteApiRestService { ); } - createBooking(bookingRequest: Booking): Observable<any> { + createBooking(bookingRequest: Booking) { return this.http.post('http://localhost:8080/bookings', bookingRequest); } @@ -65,8 +64,9 @@ export class ClienteApiRestService { ); } - getAllUsers(): Observable<User[]> { - return this.http.get<User[]>('http://localhost:8080/users', { observe: 'body' }); + getAllUsers() { + return this.http.get<User[]>('http://localhost:8080/users', { + observe: 'body', + }); } - } diff --git a/angular/RestClient/src/styles.css b/angular/RestClient/src/styles.css index 7e7239a2eeea2a25f548d2e04302921d28c2a27e..2b38a785ddb3df9137e3695c83f5841746135ce0 100644 --- a/angular/RestClient/src/styles.css +++ b/angular/RestClient/src/styles.css @@ -1,4 +1,12 @@ /* You can add global styles to this file, and also import other style files */ - -html, body { height: 100%; } -body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } +@tailwind base; +@tailwind components; +@tailwind utilities; +html, +body { + height: 100%; +} +body { + margin: 0; + font-family: Roboto, "Helvetica Neue", sans-serif; +} diff --git a/angular/RestClient/tailwind.config.js b/angular/RestClient/tailwind.config.js new file mode 100644 index 0000000000000000000000000000000000000000..73f743abf7a52e8820002459d0b0649938d5c78d --- /dev/null +++ b/angular/RestClient/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./src/**/*.{html,ts}"], + theme: { + extend: {}, + }, + plugins: [], +};