From 396850dbb9b320a6aa1fb02b2c568cde0c5470bc Mon Sep 17 00:00:00 2001 From: Roshan Patel Date: Sun, 21 Sep 2025 02:29:38 +0000 Subject: [PATCH 1/2] Included more rebust client side validation --- 7-bank-project/solution/app.js | 374 ++++++++++++++++++--------------- 1 file changed, 207 insertions(+), 167 deletions(-) diff --git a/7-bank-project/solution/app.js b/7-bank-project/solution/app.js index 21f1096842..bc0226ded6 100644 --- a/7-bank-project/solution/app.js +++ b/7-bank-project/solution/app.js @@ -11,34 +11,34 @@ const accountsKey = 'accounts'; // New key for all accounts // --------------------------------------------------------------------------- const routes = { - '/dashboard': { title: 'My Account', templateId: 'dashboard', init: refresh }, - '/login': { title: 'Login', templateId: 'login' } +  '/dashboard': { title: 'My Account', templateId: 'dashboard', init: refresh }, +  '/login': { title: 'Login', templateId: 'login' } }; function navigate(path) { - window.history.pushState({}, path, window.location.origin + path); - updateRoute(); +  window.history.pushState({}, path, window.location.origin + path); +  updateRoute(); } function updateRoute() { - const path = window.location.pathname; - const route = routes[path]; +  const path = window.location.pathname; +  const route = routes[path]; - if (!route) { - return navigate('/dashboard'); - } +  if (!route) { +    return navigate('/dashboard'); +  } - const template = document.getElementById(route.templateId); - const view = template.content.cloneNode(true); - const app = document.getElementById('app'); - app.innerHTML = ''; - app.appendChild(view); +  const template = document.getElementById(route.templateId); +  const view = template.content.cloneNode(true); +  const app = document.getElementById('app'); +  app.innerHTML = ''; +  app.appendChild(view); - if (typeof route.init === 'function') { - route.init(); - } +  if (typeof route.init === 'function') { +    route.init(); +  } - document.title = route.title; +  document.title = route.title; } // --------------------------------------------------------------------------- @@ -46,71 +46,71 @@ function updateRoute() { // --------------------------------------------------------------------------- function getAccounts() { - return JSON.parse(localStorage.getItem(accountsKey) || '[]'); +  return JSON.parse(localStorage.getItem(accountsKey) || '[]'); } function saveAccounts(accounts) { - localStorage.setItem(accountsKey, JSON.stringify(accounts)); +  localStorage.setItem(accountsKey, JSON.stringify(accounts)); } function findAccount(user) { - const accounts = getAccounts(); - return accounts.find(acc => acc.user === user) || null; +  const accounts = getAccounts(); +  return accounts.find(acc => acc.user === user) || null; } async function getAccount(user) { - // Simulate async - return new Promise(resolve => { - setTimeout(() => { - const acc = findAccount(user); - if (!acc) resolve({ error: 'Account not found' }); - else resolve(acc); - }, 100); - }); +  // Simulate async +  return new Promise(resolve => { +    setTimeout(() => { +      const acc = findAccount(user); +      if (!acc) resolve({ error: 'Account not found' }); +      else resolve(acc); +    }, 100); +  }); } async function createAccount(accountJson) { - return new Promise(resolve => { - setTimeout(() => { - let data; - try { - data = JSON.parse(accountJson); - } catch (e) { - return resolve({ error: 'Malformed account data' }); - } - if (!data.user) return resolve({ error: 'Username required' }); - if (findAccount(data.user)) return resolve({ error: 'User already exists' }); - // Set up initial account structure - const newAcc = { - user: data.user, - description: data.description || '', - balance: 0, - currency: data.currency || 'USD', - transactions: [] - }; - const accounts = getAccounts(); - accounts.push(newAcc); - saveAccounts(accounts); - resolve(newAcc); - }, 100); - }); +  return new Promise(resolve => { +    setTimeout(() => { +      let data; +      try { +        data = JSON.parse(accountJson); +      } catch (e) { +        return resolve({ error: 'Malformed account data' }); +      } +      if (!data.user) return resolve({ error: 'Username required' }); +      if (findAccount(data.user)) return resolve({ error: 'User already exists' }); +      // Set up initial account structure +      const newAcc = { +        user: data.user, +        description: data.description || '', +        balance: 0, +        currency: data.currency || 'USD', +        transactions: [] +      }; +      const accounts = getAccounts(); +      accounts.push(newAcc); +      saveAccounts(accounts); +      resolve(newAcc); +    }, 100); +  }); } async function createTransaction(user, transactionJson) { - return new Promise(resolve => { - setTimeout(() => { - const accounts = getAccounts(); - const idx = accounts.findIndex(acc => acc.user === user); - if (idx === -1) return resolve({ error: 'Account not found' }); - const tx = JSON.parse(transactionJson); - tx.amount = parseFloat(tx.amount); - tx.date = tx.date || new Date().toISOString().slice(0, 10); - accounts[idx].balance += tx.amount; - accounts[idx].transactions.push(tx); - saveAccounts(accounts); - resolve(tx); - }, 100); - }); +  return new Promise(resolve => { +    setTimeout(() => { +      const accounts = getAccounts(); +      const idx = accounts.findIndex(acc => acc.user === user); +      if (idx === -1) return resolve({ error: 'Account not found' }); +      const tx = JSON.parse(transactionJson); +      tx.amount = parseFloat(tx.amount); +      tx.date = tx.date || new Date().toISOString().slice(0, 10); +      accounts[idx].balance += tx.amount; +      accounts[idx].transactions.push(tx); +      saveAccounts(accounts); +      resolve(tx); +    }, 100); +  }); } // --------------------------------------------------------------------------- @@ -118,47 +118,87 @@ async function createTransaction(user, transactionJson) { // --------------------------------------------------------------------------- let state = Object.freeze({ - account: null +  account: null }); function updateState(property, newData) { - state = Object.freeze({ - ...state, - [property]: newData - }); - localStorage.setItem(storageKey, JSON.stringify(state.account)); +  state = Object.freeze({ +    ...state, +    [property]: newData +  }); +  localStorage.setItem(storageKey, JSON.stringify(state.account)); } // --------------------------------------------------------------------------- // Login/register // --------------------------------------------------------------------------- -async function login() { - const loginForm = document.getElementById('loginForm') - const user = loginForm.user.value; - const data = await getAccount(user); +// Client-side validation for the login form +function validateLogin(form) { + const user = form.user.value.trim(); + if (user === '') { + updateElement('loginError', 'Username cannot be empty.'); + return false; + } + updateElement('loginError', ''); // Clear previous error + return true; +} + +// Client-side validation for the register form +function validateRegister(form) { + const formData = new FormData(form); + const data = Object.fromEntries(formData); + updateElement('registerError', ''); // Clear previous error - if (data.error) { - return updateElement('loginError', data.error); + if (data.user.trim() === '') { + updateElement('registerError', 'Username is required.'); + return false; } + if (data.currency.trim() === '') { + updateElement('registerError', 'Currency is required.'); + return false; + } + return true; +} + +async function login() { +  const loginForm = document.getElementById('loginForm'); +  + // Run client-side validation first + if (!validateLogin(loginForm)) { + return; + } + +  const user = loginForm.user.value; +  const data = await getAccount(user); + +  if (data.error) { +    return updateElement('loginError', data.error); +  } - updateState('account', data); - navigate('/dashboard'); +  updateState('account', data); +  navigate('/dashboard'); } 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) { - return updateElement('registerError', result.error); +  const registerForm = document.getElementById('registerForm'); + + // Run client-side validation first + if (!validateRegister(registerForm)) { + return; } - updateState('account', result); - navigate('/dashboard'); +  const formData = new FormData(registerForm); +  const data = Object.fromEntries(formData); +  const jsonData = JSON.stringify(data); +  const result = await createAccount(jsonData); + +  if (result.error) { +    return updateElement('registerError', result.error); +  } + +  updateState('account', result); +  navigate('/dashboard'); } // --------------------------------------------------------------------------- @@ -166,99 +206,99 @@ async function register() { // --------------------------------------------------------------------------- async function updateAccountData() { - const account = state.account; - if (!account) { - return logout(); - } +  const account = state.account; +  if (!account) { +    return logout(); +  } - const data = await getAccount(account.user); - if (data.error) { - return logout(); - } +  const data = await getAccount(account.user); +  if (data.error) { +    return logout(); +  } - updateState('account', data); +  updateState('account', data); } async function refresh() { - await updateAccountData(); - updateDashboard(); +  await updateAccountData(); +  updateDashboard(); } function updateDashboard() { - const account = state.account; - if (!account) { - return logout(); - } - - updateElement('description', account.description); - updateElement('balance', account.balance.toFixed(2)); - updateElement('currency', account.currency); - - // Update transactions - const transactionsRows = document.createDocumentFragment(); - for (const transaction of account.transactions) { - const transactionRow = createTransactionRow(transaction); - transactionsRows.appendChild(transactionRow); - } - updateElement('transactions', transactionsRows); +  const account = state.account; +  if (!account) { +    return logout(); +  } + +  updateElement('description', account.description); +  updateElement('balance', account.balance.toFixed(2)); +  updateElement('balance-currency', account.currency); // Fixed ID for currency display + +  // Update transactions +  const transactionsRows = document.createDocumentFragment(); +  for (const transaction of account.transactions) { +    const transactionRow = createTransactionRow(transaction); +    transactionsRows.appendChild(transactionRow); +  } +  updateElement('transactions', transactionsRows); } 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; +  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; } function addTransaction() { - const dialog = document.getElementById('transactionDialog'); - dialog.classList.add('show'); +  const dialog = document.getElementById('transactionDialog'); +  dialog.classList.add('show'); - // Reset form - const transactionForm = document.getElementById('transactionForm'); - transactionForm.reset(); +  // Reset form +  const transactionForm = document.getElementById('transactionForm'); +  transactionForm.reset(); - // Set date to today - transactionForm.date.valueAsDate = new Date(); +  // Set date to today +  transactionForm.date.valueAsDate = new Date(); } async function confirmTransaction() { - const dialog = document.getElementById('transactionDialog'); - dialog.classList.remove('show'); +  const dialog = document.getElementById('transactionDialog'); +  dialog.classList.remove('show'); - const transactionForm = document.getElementById('transactionForm'); +  const transactionForm = document.getElementById('transactionForm'); - const formData = new FormData(transactionForm); - const jsonData = JSON.stringify(Object.fromEntries(formData)); - const data = await createTransaction(state.account.user, jsonData); +  const formData = new FormData(transactionForm); +  const jsonData = JSON.stringify(Object.fromEntries(formData)); +  const data = await createTransaction(state.account.user, jsonData); - if (data.error) { - return updateElement('transactionError', data.error); - } +  if (data.error) { +    return updateElement('transactionError', data.error); +  } - // Update local state with new transaction - const newAccount = { - ...state.account, - balance: state.account.balance + data.amount, - transactions: [...state.account.transactions, data] - } - updateState('account', newAccount); +  // Update local state with new transaction +  const newAccount = { +    ...state.account, +    balance: state.account.balance + data.amount, +    transactions: [...state.account.transactions, data] +  } +  updateState('account', newAccount); - // Update display - updateDashboard(); +  // Update display +  updateDashboard(); } async function cancelTransaction() { - const dialog = document.getElementById('transactionDialog'); - dialog.classList.remove('show'); +  const dialog = document.getElementById('transactionDialog'); +  dialog.classList.remove('show'); } function logout() { - updateState('account', null); - navigate('/login'); +  updateState('account', null); +  navigate('/login'); } // --------------------------------------------------------------------------- @@ -266,9 +306,9 @@ function logout() { // --------------------------------------------------------------------------- function updateElement(id, textOrNode) { - const element = document.getElementById(id); - element.textContent = ''; // Removes all children - element.append(textOrNode); +  const element = document.getElementById(id); +  element.textContent = ''; // Removes all children +  element.append(textOrNode); } // --------------------------------------------------------------------------- @@ -276,15 +316,15 @@ function updateElement(id, textOrNode) { // --------------------------------------------------------------------------- function init() { - // Restore state - const savedState = localStorage.getItem(storageKey); - if (savedState) { - updateState('account', JSON.parse(savedState)); - } - - // Update route for browser back/next buttons - window.onpopstate = () => updateRoute(); - updateRoute(); +  // Restore state +  const savedState = localStorage.getItem(storageKey); +  if (savedState) { +    updateState('account', JSON.parse(savedState)); +  } + +  // Update route for browser back/next buttons +  window.onpopstate = () => updateRoute(); +  updateRoute(); } init(); From f920e8c227334d8dfd3e78ac1d929f7f6e97bacc Mon Sep 17 00:00:00 2001 From: Roshan Patel Date: Fri, 3 Oct 2025 20:59:37 +0530 Subject: [PATCH 2/2] Update 7-bank-project/solution/app.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 7-bank-project/solution/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/7-bank-project/solution/app.js b/7-bank-project/solution/app.js index bc0226ded6..0175645566 100644 --- a/7-bank-project/solution/app.js +++ b/7-bank-project/solution/app.js @@ -232,7 +232,7 @@ function updateDashboard() {   updateElement('description', account.description);   updateElement('balance', account.balance.toFixed(2)); -  updateElement('balance-currency', account.currency); // Fixed ID for currency display +  updateElement('currency', account.currency); // Fixed ID for currency display   // Update transactions   const transactionsRows = document.createDocumentFragment();