diff --git a/package-lock.json b/package-lock.json index 1349153..d79848d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.21.4", @@ -964,6 +965,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1129,6 +1131,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001449", "electron-to-chromium": "^1.4.284", @@ -1450,6 +1453,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", @@ -2837,6 +2841,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3277,6 +3282,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz", "integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==", "dev": true, + "peer": true, "dependencies": { "esbuild": "^0.17.5", "postcss": "^8.4.23", @@ -3436,6 +3442,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", "dev": true, + "peer": true, "requires": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.21.4", @@ -4004,7 +4011,8 @@ "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true + "dev": true, + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -4121,6 +4129,7 @@ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, + "peer": true, "requires": { "caniuse-lite": "^1.0.30001449", "electron-to-chromium": "^1.4.284", @@ -4365,6 +4374,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", "dev": true, + "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", @@ -5342,6 +5352,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "requires": { "loose-envify": "^1.1.0" } @@ -5638,6 +5649,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz", "integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==", "dev": true, + "peer": true, "requires": { "esbuild": "^0.17.5", "fsevents": "~2.3.2", diff --git a/src/App.jsx b/src/App.jsx index 98d0f49..67fdca0 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,11 +1,108 @@ import "./App.css"; +import { IdCard } from "./components/IdCard/IdCard"; +import { Greetings } from "./components/Greetings/Greetings"; +import { RandomNumber } from "./components/Random/RandomNumber"; +import { BoxColor } from "./components/BoxColor/BoxColor"; +import { CreditCard } from "./components/CreditCard/CreditCard"; +import { Rating } from "./components/Rating/Rating"; +import { DriverCard } from "./components/DriverCard/DriverCard"; function App() { - return ( -
-

LAB | React Training

-
- ); + return ( +
+

LAB | React Training

+ + +
+ + Ludwig + François + Maria + John + +
+ + + + + + + + + + + + + + 0 + 1.49 + 1.5 + 3 + 4 + 5 + + + + +
+ ); } export default App; diff --git a/src/components/BoxColor/BoxColor.jsx b/src/components/BoxColor/BoxColor.jsx new file mode 100644 index 0000000..b6f8906 --- /dev/null +++ b/src/components/BoxColor/BoxColor.jsx @@ -0,0 +1,19 @@ +export function BoxColor({ r, g, b }) { + const backgroundColor = `rgb(${r}, ${g}, ${b})`; + + const boxStyle = { + backgroundColor: backgroundColor, + width: "300px", + height: "100px", + display: "flex", + justifyContent: "center", + alignItems: "center", + margin: "10px 0", + color: r + g + b > 382 ? "black" : "white", // text color contrast + fontWeight: "bold", + border: "1px solid #000", + borderRadius: "8px", + }; + + return
{backgroundColor}
; +} diff --git a/src/components/CreditCard/CreditCard.jsx b/src/components/CreditCard/CreditCard.jsx new file mode 100644 index 0000000..04fb270 --- /dev/null +++ b/src/components/CreditCard/CreditCard.jsx @@ -0,0 +1,72 @@ +export function CreditCard({ + type, + number, + expirationMonth, + expirationYear, + bank, + owner, + bgColor, + color, +}) { + // Mask all digits except the last 4 + const maskedNumber = `•••• •••• •••• ${number.slice(-4)}`; + + // Format month to always have two digits + const formattedMonth = expirationMonth.toString().padStart(2, "0"); + + // Determine card logo + const logo = + type === "Visa" + ? "https://upload.wikimedia.org/wikipedia/commons/4/41/Visa_Logo.png" + : "https://upload.wikimedia.org/wikipedia/commons/0/04/Mastercard-logo.png"; + + const cardStyle = { + backgroundColor: bgColor, + color: color, + width: "350px", + borderRadius: "15px", + padding: "20px", + fontFamily: "Arial, sans-serif", + display: "flex", + flexDirection: "column", + justifyContent: "space-between", + margin: "10px 0", + minHeight: "180px", + boxShadow: "0 4px 8px rgba(0,0,0,0.2)", + }; + + const topRowStyle = { + display: "flex", + justifyContent: "flex-end", + }; + + const bottomRowStyle = { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + marginTop: "20px", + fontSize: "0.9em", + }; + + const numberStyle = { + fontSize: "1.5em", + letterSpacing: "2px", + margin: "20px 0", + }; + + return ( +
+
+ {type} +
+
{maskedNumber}
+
+
+ Expires {formattedMonth}/{expirationYear.toString().slice(-2)} +
+
{bank}
+
+
{owner}
+
+ ); +} diff --git a/src/components/DriverCard/DriverCard.jsx b/src/components/DriverCard/DriverCard.jsx new file mode 100644 index 0000000..34e77ea --- /dev/null +++ b/src/components/DriverCard/DriverCard.jsx @@ -0,0 +1,44 @@ +export function DriverCard({ name, rating, img, car }) { + const cardStyle = { + display: "flex", + alignItems: "center", + backgroundColor: "#455eb5", + color: "white", + borderRadius: "10px", + padding: "20px", + margin: "10px 0", + maxWidth: "500px", + }; + + const imgStyle = { + width: "100px", + height: "100px", + borderRadius: "50%", + objectFit: "cover", + marginRight: "20px", + }; + + const infoStyle = { + display: "flex", + flexDirection: "column", + }; + + // Convert rating to nearest integer and display stars + const roundedRating = Math.round(rating); + const stars = Array.from({ length: 5 }, (_, i) => + i < roundedRating ? "★" : "☆", + ).join(" "); + + return ( +
+ {name} +
+

{name}

+

{stars}

+

+ {car.model} - {car.licensePlate} +

+
+
+ ); +} diff --git a/src/components/Greetings/Greetings.jsx b/src/components/Greetings/Greetings.jsx new file mode 100644 index 0000000..810a544 --- /dev/null +++ b/src/components/Greetings/Greetings.jsx @@ -0,0 +1,33 @@ +export function Greetings({ lang, children }) { + const divStyle = { + border: "3px solid black", + margin: "15px", + padding: "20px", + fontSize: "30px", + }; + + let greeting; + + switch (lang) { + case "de": + greeting = "Hallo"; + break; + case "en": + greeting = "Hello"; + break; + case "es": + greeting = "Hola"; + break; + case "fr": + greeting = "Bonjour"; + break; + default: + greeting = "Hello"; + } + + return ( +
+ {greeting} {children} +
+ ); +} diff --git a/src/components/IdCard/IdCard.jsx b/src/components/IdCard/IdCard.jsx new file mode 100644 index 0000000..03576b7 --- /dev/null +++ b/src/components/IdCard/IdCard.jsx @@ -0,0 +1,29 @@ +import "./idCard.css"; + +export function IdCard(props) { + const { firstName, lastName, gender, height, birth, picture } = props; + return ( + <> +
+ foto de la persona +
+

+ First name: {firstName} +

+

+ Last name : {lastName} +

+

+ Gender : {gender} +

+

+ Height: {height} +

+

+ Birth: {birth.toLocaleDateString()} +

+
+
+ + ); +} diff --git a/src/components/IdCard/idCard.css b/src/components/IdCard/idCard.css new file mode 100644 index 0000000..8f032c3 --- /dev/null +++ b/src/components/IdCard/idCard.css @@ -0,0 +1,6 @@ +.box-container { + display: flex; + border: 2px solid black; + gap: 20px; + margin: 15px; +} diff --git a/src/components/Random/RandomNumber.jsx b/src/components/Random/RandomNumber.jsx new file mode 100644 index 0000000..d4a7f93 --- /dev/null +++ b/src/components/Random/RandomNumber.jsx @@ -0,0 +1,14 @@ +export function RandomNumber({ min, max }) { + const getRandomInt = () => { + let integer = Math.floor(Math.random() * (max - min + 1)) + min; + return integer; + }; + + return ( + <> +

+ Random value between {min} and {max} = {getRandomInt()} +

+ + ); +} diff --git a/src/components/Rating/Rating.jsx b/src/components/Rating/Rating.jsx new file mode 100644 index 0000000..faacfa5 --- /dev/null +++ b/src/components/Rating/Rating.jsx @@ -0,0 +1,13 @@ +export function Rating({ children }) { + const roundedRating = Math.round(children); + + const stars = []; + for (let i = 1; i <= 5; i++) { + stars.push(i <= roundedRating ? "★" : "☆"); + } + return ( + <> +
{stars.join(" ")}
; + + ); +}