Local Storage
Objeto localStorage
const name = 'value';
localStorage.setItem('name', name);
console.log(localStorage.getItem('name'));
//=> value
localStorage.setItem('person', JSON.stringify({ name: 'John' }));
console.log(JSON.parse(localStorage.getItem('name')));
//=> { name: 'John' }
const name = 'value';
localStorage.setItem('name', name);
console.log(localStorage.getItem('name'));
//=> value
localStorage.setItem('person', JSON.stringify({ name: 'John' }));
console.log(JSON.parse(localStorage.getItem('name')));
//=> { name: 'John' }
Alternativas Remotas
Invest-app (CRUD)
Arquivos
invest-app
├── css
│ └── style.css
├── index.html
├── js
│ ├── components
│ │ ├── InvestmentCard.js
│ │ ├── InvestmentForm.js
│ │ └── Modal.js
│ ├── data
│ │ └── seed.js
│ ├── lib
│ │ ├── dom.js
│ │ ├── format.js
│ │ └── investments.js
│ ├── main.js
│ └── services
│ └── storage.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ └── vite.svg
└── tailwind.config.js
Arquivos
invest-app
├── css
│ └── style.css
├── index.html
├── js
│ ├── components
│ │ ├── InvestmentCard.js
│ │ ├── InvestmentForm.js
│ │ └── Modal.js
│ ├── data
│ │ └── seed.js
│ ├── lib
│ │ ├── dom.js
│ │ ├── format.js
│ │ └── investments.js
│ ├── main.js
│ └── services
│ └── storage.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ └── vite.svg
└── tailwind.config.js
Local Storage
/codes/w3c/local-storage/invest-app/js/data/seed.js
export const investments = [
{
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
},
{
id: 'bb0a4c9b-8eea-4d79-a248-39c8b846fa9e',
name: 'Tesouro IPCA 2029',
value: 10000,
origin: 'Tesouro Nacional',
category: 'IPCA',
created_at: '2023-08-22T00:00:00-03:00',
interest: 'IPCA + 5,83%',
},
];
/codes/w3c/local-storage/invest-app/js/data/seed.js
export const investments = [
{
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
},
{
id: 'bb0a4c9b-8eea-4d79-a248-39c8b846fa9e',
name: 'Tesouro IPCA 2029',
value: 10000,
origin: 'Tesouro Nacional',
category: 'IPCA',
created_at: '2023-08-22T00:00:00-03:00',
interest: 'IPCA + 5,83%',
},
];
/codes/w3c/local-storage/invest-app/js/services/storage.js
import { v4 as uuidv4 } from 'uuid';
function storageInsert(key, data) {
if (typeof data === 'object') {
data = JSON.stringify(data);
}
localStorage.setItem(`@invest-app:${key}`, data);
}
function storageSelect(key, isJSON = true) {
let data = localStorage.getItem(`@invest-app:${key}`);
if (isJSON) {
data = JSON.parse(data);
}
return data;
}
function load(resource, dataset) {
if (storageSelect('loaded', false) !== 'ok') {
storageInsert(resource, dataset);
storageInsert('loaded', 'ok');
}
}
function create(resourse, data) {}
function read(resourse, id) {}
function update(resourse, id, data) {}
function remove(resourse, id) {}
export default { load, create, read, update, remove };
/codes/w3c/local-storage/invest-app/js/services/storage.js
import { v4 as uuidv4 } from 'uuid';
function storageInsert(key, data) {
if (typeof data === 'object') {
data = JSON.stringify(data);
}
localStorage.setItem(`@invest-app:${key}`, data);
}
function storageSelect(key, isJSON = true) {
let data = localStorage.getItem(`@invest-app:${key}`);
if (isJSON) {
data = JSON.parse(data);
}
return data;
}
function load(resource, dataset) {
if (storageSelect('loaded', false) !== 'ok') {
storageInsert(resource, dataset);
storageInsert('loaded', 'ok');
}
}
function create(resourse, data) {}
function read(resourse, id) {}
function update(resourse, id, data) {}
function remove(resourse, id) {}
export default { load, create, read, update, remove };
Create a investment
/codes/w3c/local-storage/invest-app/js/services/storage.js
function create(resource, data) {
const datas = storageSelect(resource);
data = { ...data, id: uuidv4() };
storageInsert(resource, [...datas, data]);
return data;
}
/codes/w3c/local-storage/invest-app/js/services/storage.js
function create(resource, data) {
const datas = storageSelect(resource);
data = { ...data, id: uuidv4() };
storageInsert(resource, [...datas, data]);
return data;
}
import Storage from './services/storage.js';
const investment = {
name: "Tesouro Selic 2029",
value: 10000,
origin: "Tesouro Direto",
category: "Pós",
interest: "100% Selic",
created_at: "2021-09-10T00:00:00-03:00",
};
Storage.create('investments', investment);
import Storage from './services/storage.js';
const investment = {
name: "Tesouro Selic 2029",
value: 10000,
origin: "Tesouro Direto",
category: "Pós",
interest: "100% Selic",
created_at: "2021-09-10T00:00:00-03:00",
};
Storage.create('investments', investment);
Read investments
/codes/w3c/local-storage/invest-app/js/services/storage.js
function read(resource, id) {
const datas = storageSelect(resource);
if (id) {
return datas.find((data) => data.id === id);
} else {
return datas;
}
}
/codes/w3c/local-storage/invest-app/js/services/storage.js
function read(resource, id) {
const datas = storageSelect(resource);
if (id) {
return datas.find((data) => data.id === id);
} else {
return datas;
}
}
import Storage from './services/storage.js';
Storage.read('investments');
Storage.read('investments', 1);
import Storage from './services/storage.js';
Storage.read('investments');
Storage.read('investments', 1);
Update a investment
/codes/w3c/local-storage/invest-app/js/services/storage.js
function update(resource, id, data) {
const dataset = storageSelect(resource);
const index = dataset.findIndex((data) => data.id === id);
if (index >= 0) {
data = { id, ...data };
dataset[index] = { ...dataset[index], ...data };
storageInsert(resource, dataset);
return data;
} else {
return false;
}
}
/codes/w3c/local-storage/invest-app/js/services/storage.js
function update(resource, id, data) {
const dataset = storageSelect(resource);
const index = dataset.findIndex((data) => data.id === id);
if (index >= 0) {
data = { id, ...data };
dataset[index] = { ...dataset[index], ...data };
storageInsert(resource, dataset);
return data;
} else {
return false;
}
}
import Storage from './services/storage.js';
Storage.update('investments', 1, { value: 15000 });
import Storage from './services/storage.js';
Storage.update('investments', 1, { value: 15000 });
Delete a investment
/codes/w3c/local-storage/invest-app/js/services/storage.js
function remove(resource, id) {
const dataset = storageSelect(resource);
const index = dataset.findIndex((data) => data.id === id);
if (index >= 0) {
dataset.splice(index, 1);
}
storageInsert(resource, dataset);
}
/codes/w3c/local-storage/invest-app/js/services/storage.js
function remove(resource, id) {
const dataset = storageSelect(resource);
const index = dataset.findIndex((data) => data.id === id);
if (index >= 0) {
dataset.splice(index, 1);
}
storageInsert(resource, dataset);
}
import Storage from './services/storage.js';
Storage.remove('investments', 1);
import Storage from './services/storage.js';
Storage.remove('investments', 1);
Front-end
$ npm i @iconify/iconify
$ npm i preline
$ npm i @preline/overlay
$ npm i @iconify/iconify
$ npm i preline
$ npm i @preline/overlay
/codes/w3c/local-storage/invest-app/tailwind.config.js
module.exports = {
darkMode: 'class',
content: ['./**/*.{html,js}', 'node_modules/preline/dist/*.js'],
theme: {
extend: {},
},
plugins: [require('preline/plugin')],
};
/codes/w3c/local-storage/invest-app/tailwind.config.js
module.exports = {
darkMode: 'class',
content: ['./**/*.{html,js}', 'node_modules/preline/dist/*.js'],
theme: {
extend: {},
},
plugins: [require('preline/plugin')],
};
/codes/w3c/local-storage/invest-app/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Invest App</title>
</head>
<body class="bg-gray-100">
<div class="container mx-auto lg:max-w-screen-lg">
<h1 class="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div class="investments grid grid-cols-3 gap-3"></div>
</div>
<script type="module" src="/js/main.js"></script>
</body>
</html>
/codes/w3c/local-storage/invest-app/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Invest App</title>
</head>
<body class="bg-gray-100">
<div class="container mx-auto lg:max-w-screen-lg">
<h1 class="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div class="investments grid grid-cols-3 gap-3"></div>
</div>
<script type="module" src="/js/main.js"></script>
</body>
</html>
/codes/w3c/local-storage/invest-app/js/main.js
import 'preline';
import '@iconify/iconify';
import InvestmentForm from './components/InvestmentForm';
import Modal from './components/Modal';
import Investments from './lib/investments';
import Storage from './services/storage';
import { investments } from './data/seed';
import '../css/style.css';
Storage.load('investments', investments);
Investments.load();
InvestmentForm.create();
Modal.create();
/codes/w3c/local-storage/invest-app/js/main.js
import 'preline';
import '@iconify/iconify';
import InvestmentForm from './components/InvestmentForm';
import Modal from './components/Modal';
import Investments from './lib/investments';
import Storage from './services/storage';
import { investments } from './data/seed';
import '../css/style.css';
Storage.load('investments', investments);
Investments.load();
InvestmentForm.create();
Modal.create();
Utilitários
/codes/w3c/local-storage/invest-app/js/lib/dom.js
export const $ = (selector) => document.querySelector(selector);
/codes/w3c/local-storage/invest-app/js/lib/dom.js
export const $ = (selector) => document.querySelector(selector);
/codes/w3c/local-storage/invest-app/js/lib/format.js
export function formatCurrency(currency) {
return currency.toLocaleString('pt-BR', {
style: 'currency',
currency: 'BRL',
});
}
export function formatDate(value, pattern) {
const date = new Date(value).toLocaleDateString('pt-br');
if (pattern === 'ymd') {
return date.split('/').reverse().join('-');
} else {
return date;
}
}
/codes/w3c/local-storage/invest-app/js/lib/format.js
export function formatCurrency(currency) {
return currency.toLocaleString('pt-BR', {
style: 'currency',
currency: 'BRL',
});
}
export function formatDate(value, pattern) {
const date = new Date(value).toLocaleDateString('pt-br');
if (pattern === 'ymd') {
return date.split('/').reverse().join('-');
} else {
return date;
}
}
/codes/w3c/local-storage/invest-app/js/lib/investments.js
import InvestmentCard from '../components/InvestmentCard';
import Storage from '../services/storage';
function load() {
const investments = Storage.read('investments');
investments.forEach(InvestmentCard.create);
}
function create(investment) {
delete investment.id;
const createdInvestment = Storage.create('investments', investment);
InvestmentCard.create(createdInvestment);
}
function update(investment) {
const { id } = investment;
const updatedInvestment = Storage.update('investments', id, investment);
InvestmentCard.update(updatedInvestment);
}
function remove(investment) {
const { id } = investment;
Storage.remove('investments', id);
InvestmentCard.remove(id);
}
export default { load, create, update, remove };
/codes/w3c/local-storage/invest-app/js/lib/investments.js
import InvestmentCard from '../components/InvestmentCard';
import Storage from '../services/storage';
function load() {
const investments = Storage.read('investments');
investments.forEach(InvestmentCard.create);
}
function create(investment) {
delete investment.id;
const createdInvestment = Storage.create('investments', investment);
InvestmentCard.create(createdInvestment);
}
function update(investment) {
const { id } = investment;
const updatedInvestment = Storage.update('investments', id, investment);
InvestmentCard.update(updatedInvestment);
}
function remove(investment) {
const { id } = investment;
Storage.remove('investments', id);
InvestmentCard.remove(id);
}
export default { load, create, update, remove };
Componentes
/codes/w3c/local-storage/invest-app/js/components/InvestmentCard.js
import Investments from '../lib/investments';
import InvestmentForm from './InvestmentForm';
import { $ } from '../lib/dom';
import { formatCurrency, formatDate } from '../lib/format';
import { HSOverlay } from 'preline';
function create(investment) {
const card = `
<div
id="investment-${investment.id}"
class="bg-white shadow-md rounded-lg p-4 relative"
>
<div class="flex justify-between items-center">
<h3 class="investment-name text-lg font-semibold text-gray-700">
${investment.name}
</h3>
<p class="investment-value text-lg font-semibold text-gray-700">
${formatCurrency(investment.value / 100)}
</p>
</div>
<div class="mt-4">
<p class="text-sm text-gray-500">
<span class="font-bold">Origem:</span>
<span class="investment-origin">
${investment.origin}
</span>
</p>
<p class="text-sm text-gray-500">
<span class="font-bold">Categoria:</span>
<span class="investment-category">
${investment.category}
</span>
</p>
<p class="text-sm text-gray-500">
<span class="font-bold">Taxa:</span>
<span class="investment-interest">
${investment.interest}
</span>
</p>
<p class="text-sm text-gray-500">
<span class="font-bold">Data:</span>
<span class="investment-created_at">
${formatDate(investment.created_at)}
</span>
</p>
</div>
<div class="absolute bottom-4 right-4 inline-flex">
<span
class="icon-trash mr-1 text-gray-400 hover:text-gray-700 cursor-pointer"
>
<span
class="iconify"
data-icon="solar:trash-bin-minimalistic-broken"
>
</span>
</span>
<span
class="icon-pencil text-gray-400 hover:text-gray-700 cursor-pointer"
>
<span
class="iconify"
data-icon="tabler:pencil"
>
</span>
</span>
</div>
</div>
`;
$('.investments').insertAdjacentHTML('beforeend', card);
$(`#investment-${investment.id} .icon-pencil`).onclick = () => {
InvestmentForm.setValues(investment);
InvestmentForm.handleSubmit(Investments.update);
HSOverlay.open('#investment-drawer');
};
$(`#investment-${investment.id} .icon-trash`).onclick = () => {
$(`.modal .investment-name`).innerText = investment.name;
$(`.modal .remove-investment-btn`).onclick = () =>
Investments.remove(investment);
HSOverlay.open('#hs-basic-modal');
};
}
function update({ id, name, value, origin, category, interest, created_at }) {
value = formatCurrency(value / 100);
created_at = formatDate(created_at);
$(`#investment-${id} .investment-name`).innerText = name;
$(`#investment-${id} .investment-value`).innerText = value;
$(`#investment-${id} .investment-origin`).innerText = origin;
$(`#investment-${id} .investment-category`).innerText = category;
$(`#investment-${id} .investment-interest`).innerText = interest;
$(`#investment-${id} .investment-created_at`).innerText = created_at;
}
function remove(id) {
$(`#investment-${id}`).remove();
}
export default { create, update, remove };
/codes/w3c/local-storage/invest-app/js/components/InvestmentCard.js
import Investments from '../lib/investments';
import InvestmentForm from './InvestmentForm';
import { $ } from '../lib/dom';
import { formatCurrency, formatDate } from '../lib/format';
import { HSOverlay } from 'preline';
function create(investment) {
const card = `
<div
id="investment-${investment.id}"
class="bg-white shadow-md rounded-lg p-4 relative"
>
<div class="flex justify-between items-center">
<h3 class="investment-name text-lg font-semibold text-gray-700">
${investment.name}
</h3>
<p class="investment-value text-lg font-semibold text-gray-700">
${formatCurrency(investment.value / 100)}
</p>
</div>
<div class="mt-4">
<p class="text-sm text-gray-500">
<span class="font-bold">Origem:</span>
<span class="investment-origin">
${investment.origin}
</span>
</p>
<p class="text-sm text-gray-500">
<span class="font-bold">Categoria:</span>
<span class="investment-category">
${investment.category}
</span>
</p>
<p class="text-sm text-gray-500">
<span class="font-bold">Taxa:</span>
<span class="investment-interest">
${investment.interest}
</span>
</p>
<p class="text-sm text-gray-500">
<span class="font-bold">Data:</span>
<span class="investment-created_at">
${formatDate(investment.created_at)}
</span>
</p>
</div>
<div class="absolute bottom-4 right-4 inline-flex">
<span
class="icon-trash mr-1 text-gray-400 hover:text-gray-700 cursor-pointer"
>
<span
class="iconify"
data-icon="solar:trash-bin-minimalistic-broken"
>
</span>
</span>
<span
class="icon-pencil text-gray-400 hover:text-gray-700 cursor-pointer"
>
<span
class="iconify"
data-icon="tabler:pencil"
>
</span>
</span>
</div>
</div>
`;
$('.investments').insertAdjacentHTML('beforeend', card);
$(`#investment-${investment.id} .icon-pencil`).onclick = () => {
InvestmentForm.setValues(investment);
InvestmentForm.handleSubmit(Investments.update);
HSOverlay.open('#investment-drawer');
};
$(`#investment-${investment.id} .icon-trash`).onclick = () => {
$(`.modal .investment-name`).innerText = investment.name;
$(`.modal .remove-investment-btn`).onclick = () =>
Investments.remove(investment);
HSOverlay.open('#hs-basic-modal');
};
}
function update({ id, name, value, origin, category, interest, created_at }) {
value = formatCurrency(value / 100);
created_at = formatDate(created_at);
$(`#investment-${id} .investment-name`).innerText = name;
$(`#investment-${id} .investment-value`).innerText = value;
$(`#investment-${id} .investment-origin`).innerText = origin;
$(`#investment-${id} .investment-category`).innerText = category;
$(`#investment-${id} .investment-interest`).innerText = interest;
$(`#investment-${id} .investment-created_at`).innerText = created_at;
}
function remove(id) {
$(`#investment-${id}`).remove();
}
export default { create, update, remove };
/codes/w3c/local-storage/invest-app/js/components/InvestmentForm.js
import Investments from '../lib/investments';
import { $ } from '../lib/dom';
import { formatDate } from '../lib/format';
function setValues({
id,
name,
value,
origin,
category,
interest,
created_at,
}) {
const form = $('form');
value = value / 100;
created_at = formatDate(created_at, 'ymd');
form.id.value = id;
form.name.value = name;
form.value.value = value;
form.origin.value = origin;
form.category.value = category;
form.interest.value = interest;
form.created_at.value = created_at;
}
function getValues() {
const investment = Object.fromEntries(new FormData($('form')));
const value = Number(investment.value) * 100;
const created_at = new Date(
investment.created_at + 'T00:00:00-03:00'
).toISOString();
return { ...investment, value, created_at };
}
function create() {
const newInvestmentBtn = `
<div class="fixed bottom-8 right-8">
<button
type="button"
class="new-investment-btn py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
data-hs-overlay="#investment-drawer"
>
+
</button>
</div>
`;
const form = `
<form id="form">
<input
type="hidden"
id="id"
name="id"
>
<div class="mb-3">
<label
for="name"
class="block text-sm font-medium mb-2 dark:text-white"
>
Nome
</label>
<input
type="text"
id="name"
name="name"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="value"
class="block text-sm font-medium mb-2 dark:text-white"
>
Valor
</label>
<input
type="number"
id="value"
name="value"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="origin"
class="block text-sm font-medium mb-2 dark:text-white"
>
Origem
</label>
<input
type="text"
id="origin"
name="origin"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="category"
class="block text-sm font-medium mb-2 dark:text-white"
>
Categoria
</label>
<input
type="text"
id="category"
name="category"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="interest"
class="block text-sm font-medium mb-2 dark:text-white"
>
Taxa
</label>
<input
type="text"
id="interest"
name="interest"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="created_at"
class="block text-sm font-medium mb-2 dark:text-white"
>
Data
</label>
<input
type="date"
id="created_at"
name="created_at"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div>
<button
type="submit"
class="py-3 px-4 inline-flex w-full justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
data-hs-overlay="#investment-drawer"
>
Enviar
</button>
</div>
</form>
`;
const drawer = `
<div
id="investment-drawer"
class="hs-overlay hs-overlay-open:translate-x-0 overflow-y-auto hidden translate-x-full fixed top-0 right-0 transition-all duration-300 transform h-full max-w-xs w-full w-full z-[60] bg-white border-l dark:bg-gray-800 dark:border-gray-700"
tabindex="-1"
>
<div
class="flex justify-between items-center py-3 px-4 border-b dark:border-gray-700"
>
<h3 class="font-bold text-gray-800 dark:text-white">Investimento</h3>
<button
type="button"
class="investment-drawer-close inline-flex flex-shrink-0 justify-center items-center h-8 w-8 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-white text-sm dark:text-gray-500 dark:hover:text-gray-400 dark:focus:ring-gray-700 dark:focus:ring-offset-gray-800"
data-hs-overlay="#investment-drawer"
>
<span class="sr-only">Cadastro de Investimento</span>
<svg
class="w-3.5 h-3.5"
width="8"
height="8"
viewBox="0 0 8 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.258206 1.00652C0.351976 0.912791 0.479126 0.860131 0.611706 0.860131C0.744296 0.860131 0.871447 0.912791 0.965207 1.00652L3.61171 3.65302L6.25822 1.00652C6.30432 0.958771 6.35952 0.920671 6.42052 0.894471C6.48152 0.868271 6.54712 0.854471 6.61352 0.853901C6.67992 0.853321 6.74572 0.865971 6.80722 0.891111C6.86862 0.916251 6.92442 0.953381 6.97142 1.00032C7.01832 1.04727 7.05552 1.1031 7.08062 1.16454C7.10572 1.22599 7.11842 1.29183 7.11782 1.35822C7.11722 1.42461 7.10342 1.49022 7.07722 1.55122C7.05102 1.61222 7.01292 1.6674 6.96522 1.71352L4.31871 4.36002L6.96522 7.00648C7.05632 7.10078 7.10672 7.22708 7.10552 7.35818C7.10442 7.48928 7.05182 7.61468 6.95912 7.70738C6.86642 7.80018 6.74102 7.85268 6.60992 7.85388C6.47882 7.85498 6.35252 7.80458 6.25822 7.71348L3.61171 5.06702L0.965207 7.71348C0.870907 7.80458 0.744606 7.85498 0.613506 7.85388C0.482406 7.85268 0.357007 7.80018 0.264297 7.70738C0.171597 7.61468 0.119017 7.48928 0.117877 7.35818C0.116737 7.22708 0.167126 7.10078 0.258206 7.00648L2.90471 4.36002L0.258206 1.71352C0.164476 1.61976 0.111816 1.4926 0.111816 1.36002C0.111816 1.22744 0.164476 1.10028 0.258206 1.00652Z"
fill="currentColor"
/>
</svg>
</button>
</div>
<div class="p-4">${form}</div>
</div>
${newInvestmentBtn}
`;
$('.container').insertAdjacentHTML('afterend', drawer);
$('.new-investment-btn').onclick = () => {
$('form').reset();
handleSubmit(Investments.create);
};
}
function handleSubmit(callback) {
const form = $('form');
form.onsubmit = async (event) => {
event.preventDefault();
const investment = getValues();
callback(investment);
form.reset();
};
}
export default { setValues, getValues, create, handleSubmit };
/codes/w3c/local-storage/invest-app/js/components/InvestmentForm.js
import Investments from '../lib/investments';
import { $ } from '../lib/dom';
import { formatDate } from '../lib/format';
function setValues({
id,
name,
value,
origin,
category,
interest,
created_at,
}) {
const form = $('form');
value = value / 100;
created_at = formatDate(created_at, 'ymd');
form.id.value = id;
form.name.value = name;
form.value.value = value;
form.origin.value = origin;
form.category.value = category;
form.interest.value = interest;
form.created_at.value = created_at;
}
function getValues() {
const investment = Object.fromEntries(new FormData($('form')));
const value = Number(investment.value) * 100;
const created_at = new Date(
investment.created_at + 'T00:00:00-03:00'
).toISOString();
return { ...investment, value, created_at };
}
function create() {
const newInvestmentBtn = `
<div class="fixed bottom-8 right-8">
<button
type="button"
class="new-investment-btn py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
data-hs-overlay="#investment-drawer"
>
+
</button>
</div>
`;
const form = `
<form id="form">
<input
type="hidden"
id="id"
name="id"
>
<div class="mb-3">
<label
for="name"
class="block text-sm font-medium mb-2 dark:text-white"
>
Nome
</label>
<input
type="text"
id="name"
name="name"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="value"
class="block text-sm font-medium mb-2 dark:text-white"
>
Valor
</label>
<input
type="number"
id="value"
name="value"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="origin"
class="block text-sm font-medium mb-2 dark:text-white"
>
Origem
</label>
<input
type="text"
id="origin"
name="origin"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="category"
class="block text-sm font-medium mb-2 dark:text-white"
>
Categoria
</label>
<input
type="text"
id="category"
name="category"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="interest"
class="block text-sm font-medium mb-2 dark:text-white"
>
Taxa
</label>
<input
type="text"
id="interest"
name="interest"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div class="mb-3">
<label
for="created_at"
class="block text-sm font-medium mb-2 dark:text-white"
>
Data
</label>
<input
type="date"
id="created_at"
name="created_at"
class="py-3 px-4 block w-full border border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
required
>
</div>
<div>
<button
type="submit"
class="py-3 px-4 inline-flex w-full justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-gray-500 text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-all text-sm dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-offset-gray-800"
data-hs-overlay="#investment-drawer"
>
Enviar
</button>
</div>
</form>
`;
const drawer = `
<div
id="investment-drawer"
class="hs-overlay hs-overlay-open:translate-x-0 overflow-y-auto hidden translate-x-full fixed top-0 right-0 transition-all duration-300 transform h-full max-w-xs w-full w-full z-[60] bg-white border-l dark:bg-gray-800 dark:border-gray-700"
tabindex="-1"
>
<div
class="flex justify-between items-center py-3 px-4 border-b dark:border-gray-700"
>
<h3 class="font-bold text-gray-800 dark:text-white">Investimento</h3>
<button
type="button"
class="investment-drawer-close inline-flex flex-shrink-0 justify-center items-center h-8 w-8 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 focus:ring-offset-white text-sm dark:text-gray-500 dark:hover:text-gray-400 dark:focus:ring-gray-700 dark:focus:ring-offset-gray-800"
data-hs-overlay="#investment-drawer"
>
<span class="sr-only">Cadastro de Investimento</span>
<svg
class="w-3.5 h-3.5"
width="8"
height="8"
viewBox="0 0 8 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.258206 1.00652C0.351976 0.912791 0.479126 0.860131 0.611706 0.860131C0.744296 0.860131 0.871447 0.912791 0.965207 1.00652L3.61171 3.65302L6.25822 1.00652C6.30432 0.958771 6.35952 0.920671 6.42052 0.894471C6.48152 0.868271 6.54712 0.854471 6.61352 0.853901C6.67992 0.853321 6.74572 0.865971 6.80722 0.891111C6.86862 0.916251 6.92442 0.953381 6.97142 1.00032C7.01832 1.04727 7.05552 1.1031 7.08062 1.16454C7.10572 1.22599 7.11842 1.29183 7.11782 1.35822C7.11722 1.42461 7.10342 1.49022 7.07722 1.55122C7.05102 1.61222 7.01292 1.6674 6.96522 1.71352L4.31871 4.36002L6.96522 7.00648C7.05632 7.10078 7.10672 7.22708 7.10552 7.35818C7.10442 7.48928 7.05182 7.61468 6.95912 7.70738C6.86642 7.80018 6.74102 7.85268 6.60992 7.85388C6.47882 7.85498 6.35252 7.80458 6.25822 7.71348L3.61171 5.06702L0.965207 7.71348C0.870907 7.80458 0.744606 7.85498 0.613506 7.85388C0.482406 7.85268 0.357007 7.80018 0.264297 7.70738C0.171597 7.61468 0.119017 7.48928 0.117877 7.35818C0.116737 7.22708 0.167126 7.10078 0.258206 7.00648L2.90471 4.36002L0.258206 1.71352C0.164476 1.61976 0.111816 1.4926 0.111816 1.36002C0.111816 1.22744 0.164476 1.10028 0.258206 1.00652Z"
fill="currentColor"
/>
</svg>
</button>
</div>
<div class="p-4">${form}</div>
</div>
${newInvestmentBtn}
`;
$('.container').insertAdjacentHTML('afterend', drawer);
$('.new-investment-btn').onclick = () => {
$('form').reset();
handleSubmit(Investments.create);
};
}
function handleSubmit(callback) {
const form = $('form');
form.onsubmit = async (event) => {
event.preventDefault();
const investment = getValues();
callback(investment);
form.reset();
};
}
export default { setValues, getValues, create, handleSubmit };