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 (
+
+
+

+
+
{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}
+
{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 (
+ <>
+
+

+
+
+ 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(" ")}
;
+ >
+ );
+}