diff --git a/4-bank-project/1-template-route/SOLUTION.md b/4-bank-project/1-template-route/SOLUTION.md new file mode 100644 index 0000000..d853b33 --- /dev/null +++ b/4-bank-project/1-template-route/SOLUTION.md @@ -0,0 +1,17 @@ +## Assignment + +```javascript +document.title = route.title; +``` +This code in the updateRoute function sets the title of the window when template changes. +In the same function we can write code to do the necessary template specific functions. +We can also set a specific function to the route by passing the function pointer (without parenthesis) and call the function here if it exists. +``` +if (route.templateId == 'dashboard') { + console.log('Dashboard is shown'); +} +``` + +## Challenge + +Using a new template I was able to easily show the credit page. \ No newline at end of file diff --git a/4-bank-project/1-template-route/app.js b/4-bank-project/1-template-route/app.js new file mode 100644 index 0000000..6507841 --- /dev/null +++ b/4-bank-project/1-template-route/app.js @@ -0,0 +1,43 @@ + +const routes = { + '/login': { templateId: 'login', title: 'Login' }, + '/dashboard': { templateId: 'dashboard', title: 'Dashboard' }, + '/credits': { templateId: 'credits', title: 'Credits' }, +}; + +function updateRoute() { + const path = window.location.pathname; + const route = routes[path]; + + if (!route) { + return navigate('/login'); + } + + document.title = route.title; + + if (route.templateId == 'dashboard') { + console.log('Dashboard is shown'); + } + + const template = document.getElementById(route.templateId); + const view = template.content.cloneNode(true); + const app = document.getElementById('app'); + app.innerHTML = ''; + app.appendChild(view); +} + +function navigate(path) { + window.history.pushState({}, path, path); + + updateRoute(); +} + +function onLinkClick(event) { + event.preventDefault(); + navigate(event.target.href); +} + +window.onpopstate = () => updateRoute(); +updateRoute(); + +// updateRoute('login'); \ No newline at end of file diff --git a/4-bank-project/1-template-route/index.html b/4-bank-project/1-template-route/index.html new file mode 100644 index 0000000..9d9dc76 --- /dev/null +++ b/4-bank-project/1-template-route/index.html @@ -0,0 +1,164 @@ + + + + + + Bank App + + + +
Loading...
+ + + + + \ No newline at end of file diff --git a/4-bank-project/2-forms/SOLUTION.md b/4-bank-project/2-forms/SOLUTION.md new file mode 100644 index 0000000..e4e0afe --- /dev/null +++ b/4-bank-project/2-forms/SOLUTION.md @@ -0,0 +1,8 @@ +## Assignment + +I first added the css file for each page in routes so that when document loads, the javascript will just change the current href of the link tag. +I was able to make a movie like credits scene from a project in codepen. + +## Challenge + +I created a div which would be initially hidden and when the user enters an existing username, I check the error in result of register function. \ No newline at end of file diff --git a/4-bank-project/2-forms/app.js b/4-bank-project/2-forms/app.js new file mode 100644 index 0000000..0f0486e --- /dev/null +++ b/4-bank-project/2-forms/app.js @@ -0,0 +1,75 @@ + +const routes = { + '/login': { templateId: 'login', title: 'Login', style: 'style.css' }, + '/dashboard': { templateId: 'dashboard', title: 'Dashboard' }, + '/credits': { templateId: 'credits', title: 'Credits', style: 'credits.css' }, +}; + +async function register() { + const registerForm = document.getElementById('registerForm'); + const formData = new FormData(registerForm); + const data = Object.fromEntries(formData); + const jsonData = JSON.stringify(data); + const result = await createAccount(jsonData); + if (result.error == "User already exists") + { + document.getElementById('userError').hidden = false; + } else { + console.log('Account created!', result); + } +} + +async function createAccount(account) { + try { + const response = await fetch('//localhost:5000/api/accounts', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: account + }); + return await response.json(); + } catch (error) { + return { error: error.message || 'Unknown error' }; + } +} + +function updateRoute() { + const path = window.location.pathname; + const route = routes[path]; + + if (!route) { + return navigate('/login'); + } + + if (route.style) { + const style = document.getElementById('stylesheet'); + style.href = route.style; + } + + document.title = route.title; + + if (route.templateId == 'dashboard') { + console.log('Dashboard is shown'); + } + + const template = document.getElementById(route.templateId); + const view = template.content.cloneNode(true); + const app = document.getElementById('app'); + app.innerHTML = ''; + app.appendChild(view); +} + +function navigate(path) { + window.history.pushState({}, path, path); + + updateRoute(); +} + +function onLinkClick(event) { + event.preventDefault(); + navigate(event.target.href); +} + +window.onpopstate = () => updateRoute(); +updateRoute(); + +// updateRoute('login'); \ No newline at end of file diff --git a/4-bank-project/2-forms/credits.css b/4-bank-project/2-forms/credits.css new file mode 100644 index 0000000..c724f00 --- /dev/null +++ b/4-bank-project/2-forms/credits.css @@ -0,0 +1,52 @@ +.wrapper { + position: absolute; + top: 100%; + left: 50%; + width: 400px; + margin-left: -200px; + text-align: center; + text-transform: uppercase; + color: white; + animation: 60s credits linear infinite; +} + +h1 { + color: white; +} + +* { + font: 300 30px/1 'Open Sans Condensed', sans-serif; +} + +.movie { + margin-bottom: 50px; + font-size: 50px; +} + +.job { + margin-bottom: 5px; + font-size: 18px; +} + +.name { + margin-bottom: 50px; + font-size: 35px; +} + +@keyframes credits { + 0% { + top: 100%; + } + 100% { + top: -500%; + } +} + +html, body { + height: 100%; +} + +body { + background: radial-gradient(ellipse at top left, #334455 0%, #112233 100%); + overflow: hidden; +} \ No newline at end of file diff --git a/4-bank-project/2-forms/index.html b/4-bank-project/2-forms/index.html new file mode 100644 index 0000000..1c437b6 --- /dev/null +++ b/4-bank-project/2-forms/index.html @@ -0,0 +1,189 @@ + + + + + + Bank App + + + + +
Loading...
+ + + + + + \ No newline at end of file diff --git a/4-bank-project/2-forms/style.css b/4-bank-project/2-forms/style.css new file mode 100644 index 0000000..10f83f2 --- /dev/null +++ b/4-bank-project/2-forms/style.css @@ -0,0 +1,128 @@ +.full { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +#container { + background-color:aliceblue; + border-radius: 10px; + padding: 30px; + width: 50%; + height: fit-content; + min-width: 200px; + max-width: 400px; + display: flex; + flex-direction: column; + align-items: center; +} + + +hr { + width: 50%; + border: none; + border-top: 2px solid #ccc; + margin: 20px 0; +} + +#userError { + color: red; +} +.or { + text-align: center; + font-weight: bold; + margin: 20px 0; + position: relative; + color: #666; +} + +.or::before, +.or::after { + content: ""; + display: block; + width: 44%; + height: 1px; + background-color: #000000; + position: absolute; +} + +.or::before { + left: 0%; +} + +.or::after { + right: 0%; +} + +label { + width: 100%; + display: block; + text-align: left; + margin-top: 16px; + margin-bottom: 5px; +} + +input { + border-radius: 10px; + margin: auto; + padding: 10px; + width: 100%; +} + +h1 { + color: #3584c9; +} + + +h2 { + padding: 0%; + margin: 0%; + color: #3584c9; + font-weight: bold; +} + +button { + background-color: #1f91ea; + color: white; + padding: 10px; + border-radius: 10px; + margin-top: 16px; + border: none; + cursor: pointer; +} + +body { + background-color: #38a3e7; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + overflow: hidden; +} + +input, button { + width: 100%; + box-sizing: border-box; +} + +* { + font-family: 'Arial', sans-serif; +} + +footer { + position: absolute; + bottom: 10px; + left: 10px; + width: 100%; + text-align: left; +} + +footer>a { + color: white; + text-decoration: none; + border: none; + font-weight: bold; +} \ No newline at end of file diff --git a/4-bank-project/3-data/SOLUTION.md b/4-bank-project/3-data/SOLUTION.md new file mode 100644 index 0000000..45641a9 --- /dev/null +++ b/4-bank-project/3-data/SOLUTION.md @@ -0,0 +1,7 @@ +## Challenge + +I used min function to set the width of the container dynamically if the window resizes. I also aligned the credits under the bank app header because if the window is small, the credits would display over the container. + +## Assignment + +I declared the base url global and replaced the complete url with string concatenation. To create a common function for both, I analyzed the parameters and made a params for methods, headers and body. \ No newline at end of file diff --git a/4-bank-project/3-data/app.js b/4-bank-project/3-data/app.js new file mode 100644 index 0000000..288e975 --- /dev/null +++ b/4-bank-project/3-data/app.js @@ -0,0 +1,163 @@ +let account = null; +const baseURL = '//localhost:5000'; +const accountURL = 'api/accounts'; + +const routes = { + '/login': { templateId: 'login', title: 'Login', style: 'login.css' }, + '/dashboard': { templateId: 'dashboard', title: 'Dashboard', style: 'dashboard.css', init: updateDashboard }, + '/credits': { templateId: 'credits', title: 'Credits', style: 'credits.css' }, +}; + + +// Helper function to get element by id and update its text content +function updateElement(id, textOrNode) +{ + const element = document.getElementById(id); + element.textContent = ''; + element.hidden = false; + element.append(textOrNode); +} + + +// Gets login form data and sends a request to the server +async function login() +{ + const loginForm = document.getElementById('loginForm') + const user = loginForm.user.value; + const data = await sendRequest('/api/accounts/' + encodeURIComponent(user)); + + if (data.error) { + updateElement('loginError', data.error); + return console.log('loginError', data.error); + } + + account = data; + navigate('/dashboard'); +} + + +// Gets register form data and sends a POST request to the server +async function register() +{ + const registerForm = document.getElementById('registerForm'); + const formData = new FormData(registerForm); + const data = Object.fromEntries(formData); + const jsonData = JSON.stringify(data); + const result = await sendRequest('/api/accounts', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: jsonData + }); + + if (result.error) + { + updateElement('userError', result.error); + + } else { + console.log('Account created!', result); + account = result; + navigate('/dashboard'); + } +} + + +// Helper function to send a request to the server +async function sendRequest(url, params = {}) { + try { + console.log('Sending request to:', baseURL + url); + const response = await fetch(baseURL + url, params); + return await response.json(); + } catch (error) { + return { error: error.message || 'Unknown error' }; + } +} + + +// Clones the transaction template and fills it with data +function createTransactionRow(transaction) +{ + const template = document.getElementById('transaction'); + const transactionRow = template.content.cloneNode(true); + const tr = transactionRow.querySelector('tr'); + tr.children[0].textContent = transaction.date; + tr.children[1].textContent = transaction.object; + tr.children[2].textContent = transaction.amount.toFixed(2); + return transactionRow; +} + + +// Updates the dashboard with the account data +function updateDashboard() +{ + if (!account) { + return navigate('/login'); + } + + updateElement('description', account.description); + updateElement('balance', account.balance.toFixed(2)); + updateElement('currency', account.currency); + + const transactionsRows = document.createDocumentFragment(); + + for (const transaction of account.transactions) { + const transactionRow = createTransactionRow(transaction); + transactionsRows.appendChild(transactionRow); + } + + updateElement('transactions', transactionsRows); +} + + +// On navigation, update the route and the view using templates +function updateRoute() +{ + const path = window.location.pathname; + const route = routes[path]; + + // When invalid path or home page + if (!route) { + return navigate('/login'); + } + + document.title = route.title; + + if (route.templateId == 'dashboard') { + console.log('Dashboard is shown'); + } + + const template = document.getElementById(route.templateId); + const view = template.content.cloneNode(true); + const app = document.getElementById('app'); + app.innerHTML = ''; + app.appendChild(view); + + if (route.style) { + const style = document.getElementById('stylesheet'); + style.href = route.style; + } + + if (typeof route.init === 'function') { + route.init(); + } +} + + +// Navigate to the given path +function navigate(path) +{ + window.history.pushState({}, path, path); + updateRoute(); +} + + +// Prevent default behavior and navigate to the href +function onLinkClick(event) +{ + event.preventDefault(); + navigate(event.target.href); +} + + +// Event listener for back or forward buttons +window.onpopstate = () => updateRoute(); +updateRoute(); \ No newline at end of file diff --git a/4-bank-project/3-data/credits.css b/4-bank-project/3-data/credits.css new file mode 100644 index 0000000..c724f00 --- /dev/null +++ b/4-bank-project/3-data/credits.css @@ -0,0 +1,52 @@ +.wrapper { + position: absolute; + top: 100%; + left: 50%; + width: 400px; + margin-left: -200px; + text-align: center; + text-transform: uppercase; + color: white; + animation: 60s credits linear infinite; +} + +h1 { + color: white; +} + +* { + font: 300 30px/1 'Open Sans Condensed', sans-serif; +} + +.movie { + margin-bottom: 50px; + font-size: 50px; +} + +.job { + margin-bottom: 5px; + font-size: 18px; +} + +.name { + margin-bottom: 50px; + font-size: 35px; +} + +@keyframes credits { + 0% { + top: 100%; + } + 100% { + top: -500%; + } +} + +html, body { + height: 100%; +} + +body { + background: radial-gradient(ellipse at top left, #334455 0%, #112233 100%); + overflow: hidden; +} \ No newline at end of file diff --git a/4-bank-project/3-data/dashboard.css b/4-bank-project/3-data/dashboard.css new file mode 100644 index 0000000..25f3e89 --- /dev/null +++ b/4-bank-project/3-data/dashboard.css @@ -0,0 +1,150 @@ +header { + background-color: #434454; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + width: 100%; + box-sizing: border-box; +} + +#app { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + +} + +#description { + color: #59727e; +} + +#transaction-header { + background-color: azure; + display: flex; + justify-content: space-between; + width: 100%; + padding: 10px; + box-sizing: border-box; +} + +#transactions-section { + display: flex; + flex-direction: column; + align-items: center; + background-color: #effefe; + padding: 15px 0 25px 0; + width: 100%; +} + +#dashboard-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 50%; + background-color: #effefe; + padding: 0px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +h1 { + margin: 0%; + color: white; +} + +td, th { + padding: 10px; +} + +h2 { + padding: 0%; + margin: 0%; + color: #3584c9; + font-weight: bold; +} + +a { + background-color: transparent; + color: white; + font-weight: bold; + border: 1px solid white; + padding: 10px; + border-radius: 10px; + text-decoration: none; +} + +#add-transaction { + background-color: #258ad9; + color: white; + font-weight: bold; + border: 1px solid white; + padding: 10px; + border-radius: 10px; + cursor: pointer; +} + +table { + background-color: #f5f5f5; + border-collapse: collapse; + border-radius: 10px; + width: 80%; + padding: 10px; +} + + + +tr:nth-child(even):not(:has(hr)) { + background-color: #cfe5f2; +} + +body { + display: flex; + height: 100vh; + margin: 0; + justify-content: center; + align-items: center; + background-color: #38a3e7; + overflow: hidden; +} + +section { + text-align: center; +} + +#account { + background-image: linear-gradient(to right, #79bce7, #2193eb, #79bce7); + padding: 10px; + width: 100%; + color: white; + box-sizing: border-box; +} + +#currency { + font-size: xx-large; +} + +#balance { + font-size: 4rem; + font-weight: bold; +} + +footer { + position: absolute; + bottom: 10px; + left: 10px; + width: 100%; + text-align: left; +} + +footer>a { + color: white; + text-decoration: none; + border: none; + padding: 0%; +} + +* { + font-family: 'Arial', sans-serif; +} \ No newline at end of file diff --git a/4-bank-project/3-data/index.html b/4-bank-project/3-data/index.html new file mode 100644 index 0000000..420b1ba --- /dev/null +++ b/4-bank-project/3-data/index.html @@ -0,0 +1,207 @@ + + + + + + Bank App + + + + +
Loading...
+ + + + + + + \ No newline at end of file diff --git a/4-bank-project/3-data/login.css b/4-bank-project/3-data/login.css new file mode 100644 index 0000000..11d2303 --- /dev/null +++ b/4-bank-project/3-data/login.css @@ -0,0 +1,123 @@ +#login-section, #loginForm, #registerForm, .or, #app { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +#container { + background-color:aliceblue; + border-radius: 10px; + padding: 30px; + width: min(60%, 400px);; + height: fit-content; + display: flex; + flex-direction: column; + align-items: center; +} + + +hr { + width: 50%; + border: none; + border-top: 2px solid #ccc; + margin: 20px 0; +} + +#userError, #loginError { + color: red; +} +.or { + text-align: center; + font-weight: bold; + margin: 20px 0; + position: relative; + color: #666; +} + +.or::before, +.or::after { + content: ""; + display: block; + width: 44%; + height: 1px; + background-color: #000000; + position: absolute; +} + +.or::before { + left: 0%; +} + +.or::after { + right: 0%; +} + +label { + width: 100%; + display: block; + text-align: left; + margin-top: 5px; + margin-bottom: 5px; +} + +input { + border-radius: 10px; + margin: auto; + width: 100%; +} + +h1 { + color: #3584c9; + margin: 0%; +} + + +h2 { + padding: 0%; + margin: 0%; + color: #3584c9; + font-weight: bold; +} + +footer { + width: 100%; + padding-bottom: 20px; + text-align: center; +} + +footer>a { + color: #3584c9; + text-decoration: none; + border: none; + font-weight: bold; +} + +button { + background-color: #1f91ea; + color: white; + border-radius: 10px; + border: none; + cursor: pointer; +} + +body { + background-color: #38a3e7; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + overflow: hidden; +} + +input, button { + width: 100%; + padding: 10px; + box-sizing: border-box; +} + +* { + font-family: 'Arial', sans-serif; +} \ No newline at end of file diff --git a/4-bank-project/4-state-management/SOLUTION.md b/4-bank-project/4-state-management/SOLUTION.md new file mode 100644 index 0000000..d2f59d7 --- /dev/null +++ b/4-bank-project/4-state-management/SOLUTION.md @@ -0,0 +1,7 @@ +## Assignment + +Using a new transaction template, I was able to make entry for new transactions. Then I used the helper function to forward the form to /api/accounts/"user"/transactions. After that i navigated to the dashboard for the results. + +## Challenge + +I removed storing all the attributes other than username because for login we only needed username. I also fixed an bug where if we reload the page when the state.account is null but account exist in local storage, then the user will get logged out. \ No newline at end of file diff --git a/4-bank-project/4-state-management/app.js b/4-bank-project/4-state-management/app.js new file mode 100644 index 0000000..8a7ac99 --- /dev/null +++ b/4-bank-project/4-state-management/app.js @@ -0,0 +1,231 @@ +let state = Object.freeze({ + account: null +}); +const baseURL = '//localhost:5000'; +const accountURL = 'api/accounts'; +const storageKey = 'savedAccount'; + +const routes = { + '/login': { templateId: 'login', title: 'Login', style: 'login.css' }, + '/dashboard': { templateId: 'dashboard', title: 'Dashboard', style: 'dashboard.css', init: refresh }, + '/transactions': { templateId: 'transaction-template', title: 'Transactions', style: 'transaction.css' }, + '/credits': { templateId: 'credits', title: 'Credits', style: 'credits.css' }, +}; + + +// Helper function to get element by id and update its text content +function updateElement(id, textOrNode) +{ + const element = document.getElementById(id); + element.textContent = ''; + element.hidden = false; + element.append(textOrNode); +} + + +// Gets login form data and sends a request to the server +async function login() +{ + const loginForm = document.getElementById('loginForm') + const user = loginForm.user.value; + const data = await sendRequest('/api/accounts/' + encodeURIComponent(user)); + + if (data.error) { + updateElement('loginError', data.error); + return console.log('loginError', data.error); + } + + // account = data; + localStorage.setItem(storageKey, user); + updateState('account', data); + navigate('/dashboard'); +} + +function logout() { + localStorage.removeItem(storageKey); + updateState('account', null); + navigate('/login'); +} + +// Gets register form data and sends a POST request to the server +async function register() +{ + const registerForm = document.getElementById('registerForm'); + const formData = new FormData(registerForm); + const data = Object.fromEntries(formData); + const jsonData = JSON.stringify(data); + const result = await sendRequest('/api/accounts', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: jsonData + }); + + if (result.error) + { + updateElement('userError', result.error); + + } else { + console.log('Account created!', result); + // account = result; + localStorage.setItem(storageKey, result.user); + updateState('account', result); + navigate('/dashboard'); + } +} + +// Helper function to send a request to the server +async function sendRequest(endpoint, options = {}) { + try { + console.log('Sending request to:', baseURL + endpoint); + const response = await fetch(baseURL + endpoint, options); + return await response.json(); + } catch (error) { + return { error: error.message || 'Unknown error' }; + } +} + + +function newTransaction() +{ + const transactionForm = document.getElementById('transaction-form'); + const formData = new FormData(transactionForm); + const data = Object.fromEntries(formData); + const jsonData = JSON.stringify(data); + const result = sendRequest('/api/accounts/' + encodeURIComponent(state.account.user) + '/transactions', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: jsonData + }); + if (result.error) + { + console.log('Error creating transaction', result); + } + refresh(); + navigate('/dashboard'); +} + +// Clones the transaction template and fills it with data +function createTransactionRow(transaction) +{ + const template = document.getElementById('transaction'); + const transactionRow = template.content.cloneNode(true); + const tr = transactionRow.querySelector('tr'); + tr.children[0].textContent = transaction.date; + tr.children[1].textContent = transaction.object; + tr.children[2].textContent = transaction.amount.toFixed(2); + return transactionRow; +} + + +// Updates the dashboard with the account data +function updateDashboard() +{ + const account = state.account; + if (!account) { + return navigate('/login'); + } + + updateElement('description', account.description); + updateElement('balance', account.balance.toFixed(2)); + updateElement('currency', account.currency); + + const transactionsRows = document.createDocumentFragment(); + + for (const transaction of account.transactions) { + const transactionRow = createTransactionRow(transaction); + transactionsRows.appendChild(transactionRow); + } + + updateElement('transactions', transactionsRows); +} + +async function updateAccountData() { + const account = state.account; + if (!account) { + return logout(); + } + + const data = await sendRequest('/api/accounts/' + encodeURIComponent(account.user)); + if (data.error) { + return logout(); + } + + updateState('account', data); +} + +function updateState(property, newData) { + state = Object.freeze({ + ...state, + [property]: newData + }); + localStorage.setItem(storageKey, JSON.stringify(state.account)); +} + +// On navigation, update the route and the view using templates +function updateRoute() +{ + const path = window.location.pathname; + const route = routes[path]; + + // When invalid path or home page + if (!route) { + return navigate('/dashboard'); + } + + document.title = route.title; + + if (route.templateId == 'dashboard') { + console.log('Dashboard is shown'); + } + + const template = document.getElementById(route.templateId); + const view = template.content.cloneNode(true); + const app = document.getElementById('app'); + app.innerHTML = ''; + app.appendChild(view); + + if (route.style) { + const style = document.getElementById('stylesheet'); + style.href = route.style; + } + + if (typeof route.init === 'function') { + route.init(); + } +} + +async function refresh() { + await updateAccountData(); + updateDashboard(); +} + +// Navigate to the given path +function navigate(path) +{ + window.history.pushState({}, path, path); + updateRoute(); +} + + +// Prevent default behavior and navigate to the href +function onLinkClick(event) +{ + event.preventDefault(); + navigate(event.target.href); +} + + +// Checks localStorage for an account +async function init() { + const savedAccount = localStorage.getItem(storageKey); + if (savedAccount) { + // local storage account exists but is not in state + // This allows to reload page and still be logged in + updateState('account', JSON.parse(savedAccount)); + await updateAccountData(); + } + window.onpopstate = () => updateRoute(); + updateRoute(); +} + +init(); \ No newline at end of file diff --git a/4-bank-project/4-state-management/credits.css b/4-bank-project/4-state-management/credits.css new file mode 100644 index 0000000..c724f00 --- /dev/null +++ b/4-bank-project/4-state-management/credits.css @@ -0,0 +1,52 @@ +.wrapper { + position: absolute; + top: 100%; + left: 50%; + width: 400px; + margin-left: -200px; + text-align: center; + text-transform: uppercase; + color: white; + animation: 60s credits linear infinite; +} + +h1 { + color: white; +} + +* { + font: 300 30px/1 'Open Sans Condensed', sans-serif; +} + +.movie { + margin-bottom: 50px; + font-size: 50px; +} + +.job { + margin-bottom: 5px; + font-size: 18px; +} + +.name { + margin-bottom: 50px; + font-size: 35px; +} + +@keyframes credits { + 0% { + top: 100%; + } + 100% { + top: -500%; + } +} + +html, body { + height: 100%; +} + +body { + background: radial-gradient(ellipse at top left, #334455 0%, #112233 100%); + overflow: hidden; +} \ No newline at end of file diff --git a/4-bank-project/4-state-management/dashboard.css b/4-bank-project/4-state-management/dashboard.css new file mode 100644 index 0000000..f70de6f --- /dev/null +++ b/4-bank-project/4-state-management/dashboard.css @@ -0,0 +1,156 @@ +header { + background-color: #434454; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + width: 100%; + box-sizing: border-box; +} + +#app { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + box-sizing: border-box; +} + +#description { + color: #59727e; +} + +#transaction-header { + background-color: azure; + display: flex; + justify-content: space-between; + width: 100%; + padding: 10px; + box-sizing: border-box; +} + +#transactions-section { + display: flex; + flex-direction: column; + align-items: center; + background-color: #effefe; + padding: 15px 0 25px 0; + width: 100%; + overflow-y: scroll; + max-height: 100%; +} + +#dashboard-container { + display: flex; + flex-direction: column; + align-items: center; + width: min(70%, 500px); + height: 80%; + min-width: 300px; + background-color: #effefe; + padding: 0px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + box-sizing: border-box; +} + +h1 { + margin: 0%; + color: white; +} + +td, th { + padding: 10px; +} + +h2 { + padding: 0%; + margin: 0%; + color: #3584c9; + font-weight: bold; +} + +a { + background-color: transparent; + color: white; + font-weight: bold; + border: 1px solid white; + padding: 10px; + border-radius: 10px; + text-decoration: none; +} + +#add-transaction { + background-color: #258ad9; + color: white; + font-weight: bold; + border: 1px solid white; + padding: 10px; + border-radius: 10px; + cursor: pointer; +} + +table { + background-color: #f5f5f5; + border-collapse: collapse; + border-radius: 10px; + width: 80%; + padding: 10px; +} + + + +tr:nth-child(even):not(:has(hr)) { + background-color: #cfe5f2; +} + +body { + display: flex; + height: 100vh; + margin: 0; + justify-content: center; + align-items: center; + background-color: #38a3e7; + overflow: hidden; +} + +section { + text-align: center; +} + +#account { + background-image: linear-gradient(to right, #79bce7, #2193eb, #79bce7); + padding: 10px; + width: 100%; + color: white; + box-sizing: border-box; +} + +#currency { + font-size: xx-large; +} + +#balance { + font-size: 4rem; + font-weight: bold; +} + +footer { + position: absolute; + bottom: 10px; + left: 10px; + width: 100%; + text-align: left; +} + +footer>a { + color: white; + text-decoration: none; + border: none; + padding: 0%; +} + +* { + font-family: 'Arial', sans-serif; +} \ No newline at end of file diff --git a/4-bank-project/4-state-management/index.html b/4-bank-project/4-state-management/index.html new file mode 100644 index 0000000..132f18d --- /dev/null +++ b/4-bank-project/4-state-management/index.html @@ -0,0 +1,226 @@ + + + + + + Bank App + + + + +
Loading...
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/4-bank-project/4-state-management/login.css b/4-bank-project/4-state-management/login.css new file mode 100644 index 0000000..3ec8105 --- /dev/null +++ b/4-bank-project/4-state-management/login.css @@ -0,0 +1,121 @@ +#app, #login-section, #login-container, #loginForm , #registerForm, .or{ + width: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +#login-container { + background-color:aliceblue; + border-radius: 10px; + padding: 30px; + height: fit-content; + width: min(60%, 400px);; + display: flex; + flex-direction: column; + align-items: center; +} + + +hr { + width: 50%; + border: none; + border-top: 2px solid #ccc; + margin: 20px 0; +} + +#userError, #loginError { + color: red; +} +.or { + text-align: center; + font-weight: bold; + margin: 20px 0; + position: relative; + color: #666; +} + +.or::before, .or::after { + content: ""; + display: block; + width: 44%; + height: 1px; + background-color: #000000; + position: absolute; +} + +.or::before { + left: 0%; +} + +.or::after { + right: 0%; +} + +label { + width: 100%; + display: block; + text-align: left; + margin-top: 5px; + margin-bottom: 5px; +} + +input { + border-radius: 10px; + margin: auto; + border-width: 1px; +} + +h1 { + color: #3584c9; + margin: 0%; +} + +footer { + width: 100%; + padding-bottom: 20px; + text-align: center; +} + +footer>a { + color: #3584c9; + text-decoration: none; + border: none; + font-weight: bold; +} + +button { + background-color: #1f91ea; + color: white; + border-radius: 10px; + border: none; + cursor: pointer; +} + +h2 { + padding: 0%; + margin: 0%; + color: #3584c9; + font-weight: bold; +} + +body { + overflow: hidden; + background-color: #38a3e7; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; +} + +input, button { + width: 100%; + padding: 10px; + box-sizing: border-box; +} + +* { + font-family: 'Arial', sans-serif; +} \ No newline at end of file diff --git a/4-bank-project/4-state-management/transaction.css b/4-bank-project/4-state-management/transaction.css new file mode 100644 index 0000000..d4e4fad --- /dev/null +++ b/4-bank-project/4-state-management/transaction.css @@ -0,0 +1,77 @@ + +#transaction-container { + width: 60%; + vertical-align: middle; + height: min-content; + display: flex; + flex-direction: column; + min-width: 250px; + background-color: #effefe; + border-radius: 10px; +} + +#transaction-container { + padding: 30px; +} + +label { + width: 100%; + display: block; + text-align: left; + margin-top: 18px; + margin-bottom: 5px; + font-size: small; +} + +input, a{ + border-radius: 10px; + margin: auto; + padding: 10px; + width: 100%; + box-sizing: border-box; + border-width: 1px; +} + +#button-container { + display: flex; + flex-direction: row; +} + +a { + text-decoration: none; + box-sizing:content-box; + text-align: center; + background-color: #1f91ea; + color: white; + width: 20%; + border: none; + font-weight: bold; + margin-top: 18px; + cursor: pointer; +} + +#transaction-cancel { + background-color: #effefe; + color: #1f91ea; +} + +h2 { + padding: 0%; + margin: 0%; + color: #3584c9; + font-weight: bold; + text-align: center; +} + +body { + display: flex; + height: 100vh; + margin: 0; + justify-content: center; + align-items: center; + background-color: #38a3e7; +} + +* { + font-family: 'Arial', sans-serif; +} \ No newline at end of file