├── teste.png ├── src └── tela.png ├── uml ├── teste.png └── teste.drawio ├── index.html ├── style.css ├── README.md ├── teste.drawio └── script.js /teste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thiago-rferreira/Projeto-Agenda/HEAD/teste.png -------------------------------------------------------------------------------- /src/tela.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thiago-rferreira/Projeto-Agenda/HEAD/src/tela.png -------------------------------------------------------------------------------- /uml/teste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thiago-rferreira/Projeto-Agenda/HEAD/uml/teste.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Agenda Telefônica 10 | 11 | 12 |
13 |
14 | 15 |
16 |

Agenda Telefônica

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |

29 |
30 | 31 |
32 | 33 |
34 |
35 |
36 |

Detalhe

37 |
38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /uml/teste.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | 2 | *{ 3 | padding: 0; 4 | margin: 0; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | font-family: Arial, sans-serif; 10 | text-align: center; 11 | background-color: rgb(235, 234, 234); 12 | } 13 | 14 | h1 { 15 | color: #333; 16 | } 17 | #container{ 18 | background-color: white; 19 | width: 70%; 20 | border-radius: 1rem; 21 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); 22 | padding: 2rem; 23 | } 24 | #contact-form { 25 | margin: 20px; 26 | height: fit-content; 27 | } 28 | 29 | input { 30 | padding: 10px; 31 | margin: 5px; 32 | } 33 | 34 | button { 35 | padding: 10px 20px; 36 | background-color: #007BFF; 37 | color: #fff; 38 | border: none; 39 | cursor: pointer; 40 | } 41 | 42 | #contact-list { 43 | display: flex; 44 | flex-direction: column; 45 | align-content: center; 46 | justify-content: center; 47 | align-items: center; 48 | margin: 0; 49 | padding: 0; 50 | max-height: 650px; 51 | overflow-y:scroll; 52 | margin-top: 100px; 53 | justify-content: flex-start; 54 | ;} 55 | 56 | #container1{ 57 | width: 70%; 58 | border-right: 1px solid black 59 | 60 | } 61 | 62 | .contact { 63 | display: flex; 64 | align-items: center; 65 | margin: 10px; 66 | flex-direction: row; 67 | flex-wrap: nowrap; 68 | align-content: center; 69 | justify-content: center; 70 | background-color: rgb(255, 255, 255); 71 | padding: 0.625rem; 72 | border-radius: 1rem; 73 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); 74 | } 75 | 76 | .contact img { 77 | width: 128px; 78 | border-radius: 100%; 79 | /* margin-right: 10px; */ 80 | height: 128px; 81 | padding: 1rem; 82 | } 83 | .div-info-contact{ 84 | padding: 1rem; 85 | text-align: left; 86 | } 87 | 88 | .error{ 89 | color: red; 90 | text-align: center; 91 | } 92 | 93 | .success{ 94 | color: green; 95 | text-align: center; 96 | } 97 | 98 | 99 | #container-main{ 100 | display: flex; 101 | flex-direction: row; 102 | align-content: center; 103 | width: 100%; 104 | align-items: flex-start; 105 | justify-content: space-evenly; 106 | } 107 | 108 | #container-detail{ 109 | display: flex; 110 | background-color: rgb(255, 255, 255); 111 | margin: 20px; 112 | padding: 2rem; 113 | flex-direction: column; 114 | flex-wrap: nowrap; 115 | align-content: center; 116 | justify-content: center; 117 | align-items: center; 118 | border-radius: 1rem; 119 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); 120 | font-size: 18px; 121 | } 122 | 123 | #container-detail img{ 124 | width: 200px; 125 | border-radius: 100%; 126 | margin: 20px; 127 | padding: 20px; 128 | } 129 | #card-person{ 130 | min-height: 80vh; 131 | min-width: 20rem; 132 | 133 | } 134 | 135 | #details-card{ 136 | padding: 20px; 137 | background-color: rgba(255, 255, 255, 0.695); 138 | display: flex; 139 | flex-direction: column; 140 | align-content: flex-start; 141 | align-items: flex-start; 142 | justify-content: center; 143 | flex-wrap: nowrap; 144 | } 145 | draw.io 146 | a{ 147 | font-size: 40px; 148 | margin: 20px; 149 | cursor: pointer; 150 | text-decoration: none; 151 | } 152 | 153 | .hidden{ 154 | display: none !important; 155 | } 156 | 157 | /* Estilize a barra de rolagem */ 158 | ::-webkit-scrollbar { 159 | width: 12px; /* Largura da barra de rolagem */ 160 | } 161 | 162 | /* Estilize o polegar da barra de rolagem */ 163 | ::-webkit-scrollbar-thumb { 164 | background-color: #3366cc; /* Cor do polegar da barra de rolagem */ 165 | border-radius: 6px; /* Borda arredondada do polegar da barra de rolagem */ 166 | } 167 | 168 | /* Estilize a trilha da barra de rolagem */ 169 | ::-webkit-scrollbar-track { 170 | background-color: #f0f0f0; /* Cor da trilha da barra de rolagem */ 171 | } 172 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Projeto-Agenda 2 | 3 | ![Exemplo de Uso](./src/tela.png) 4 | # Aplicação de Gerenciamento de Contatos 5 | 6 | Esta é uma aplicação de gerenciamento de contatos que permite adicionar, listar e visualizar detalhes de contatos. Ela inclui algumas funcionalidades interessantes, como cálculo do signo com base na data de nascimento e validação de campos de entrada. 7 | 8 | ## Classes 9 | 10 | ### `Contato` 11 | 12 | A classe `Contato` representa um contato e possui os seguintes atributos: 13 | 14 | - `fullname`: Nome completo do contato. 15 | - `phone`: Número de telefone fixo. 16 | - `cellphone`: Número de telefone celular. 17 | - `photo`: URL da foto do contato. 18 | - `id`: Identificador único gerado aleatoriamente. 19 | - `birthdate`: Data de nascimento do contato. 20 | - `email`: Endereço de email do contato. 21 | - `cep`: CEP do contato. 22 | - `city`: Cidade do contato. 23 | - `signo`: Signo do zodíaco com base na data de nascimento. 24 | - `age`: Idade calculada com base na data de nascimento. 25 | - `insta`: Nome de usuário do Instagram do contato. 26 | - `github`: Nome de usuário do GitHub do contato. 27 | 28 | A classe também possui dois métodos: 29 | 30 | - `getZodiacSign()`: Calcula e retorna o signo com base na data de nascimento. 31 | - `calculateAge()`: Calcula e retorna a idade com base na data de nascimento. 32 | 33 | ### `ListaContatos` 34 | 35 | A classe `ListaContatos` representa uma lista de contatos e possui um atributo `contatos`, que é um array para armazenar os contatos. Ela também possui três métodos: 36 | 37 | - `adicionarContato(contato)`: Adiciona um novo contato à lista após a validação. 38 | - `listarContatos()`: Retorna a lista de contatos. 39 | - `getContactById(id)`: Retorna um contato com base no ID fornecido. 40 | 41 | ## Funções JavaScript 42 | 43 | Além das classes, o código também inclui várias funções JavaScript: 44 | 45 | - `adicionarContato()`: Lê os dados do formulário e cria um novo contato. 46 | - `limparFormulario()`: Limpa os campos do formulário após a adição de um contato. 47 | - `exibirContatos()`: Exibe a lista de contatos na interface do usuário. 48 | - `isURLValida(url)`: Verifica se a URL da foto é válida. 49 | - `clearInputs()`: Limpa todos os campos do formulário. 50 | - `sendMSG(msg, type)`: Exibe uma mensagem na interface do usuário. 51 | - `isAnyInputEmpty()`: Verifica se algum campo do formulário está vazio. 52 | - `randomId()`: Gera um ID aleatório e verifica se já existe na lista de contatos. 53 | - `checarIdExiste(id)`: Verifica se um ID já existe na lista de contatos. 54 | - `gerarLinkWhatsapp(telefone)`: Gera um link para o WhatsApp com base no número de telefone. 55 | - `gerarLinkInstagram(insta)`: Gera um link para o perfil do Instagram com base no nome de usuário. 56 | - `gerarLinkGithub(github)`: Gera um link para o perfil do GitHub com base no nome de usuário. 57 | - `contatoDetalhe(id)`: Exibe os detalhes de um contato específico. 58 | - `exibirContatoDetalhe()`: Exibe os detalhes do contato na interface do usuário. 59 | - `formateCelular(celular)`: Formata o número de celular. 60 | - `formateCEP(cep)`: Formata o CEP. 61 | - `formateDataPTBR(data)`: Formata a data no formato DD/MM. 62 | 63 | ## Uso 64 | 65 | Para usar a aplicação, siga estes passos: 66 | 67 | 1. Abra o arquivo `index.html` em um navegador da web. 68 | 2. Preencha os campos do formulário na interface do usuário com as informações do contato que você deseja adicionar. 69 | 3. Clique no botão "Adicionar Contato" para adicionar o contato à lista. 70 | 4. A lista de contatos será exibida na interface, mostrando uma imagem do contato, seu nome e números de telefone. 71 | 5. Clique em um contato da lista para ver seus detalhes, incluindo links para WhatsApp, Instagram e GitHub. 72 | 6. Você também pode limpar todos os campos do formulário clicando no botão "Limpar Campos". 73 | 74 | Lembre-se de que a aplicação inclui validações para garantir que os campos estejam preenchidos corretamente e que a URL da foto seja válida. 75 | 76 | ## Requisitos 77 | 78 | A aplicação requer um navegador da web moderno para funcionar corretamente. Certifique-se de ter uma conexão com a Internet para carregar imagens de perfil dos contatos. 79 | 80 | ## Contribuição 81 | 82 | Sinta-se à vontade para contribuir para este projeto aberto. Você pode adicionar novas funcionalidades, corrigir erros ou melhorar a interface do usuário. Basta enviar um pull request e seu código será revisado. 83 | 84 | ## Autor 85 | 86 | Este projeto foi desenvolvido por Thiago Ferreira. 87 | -------------------------------------------------------------------------------- /teste.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | class Contato { 2 | constructor(fullname, phone, cellphone, photo, birthdate, email, cep, city, insta, github) { 3 | this.fullname = fullname; 4 | this.phone = phone; 5 | this.cellphone = cellphone; 6 | this.photo = photo; 7 | this.id = randomId(); 8 | this.birthdate = birthdate; 9 | this.email = email; 10 | this.cep = cep; 11 | this.city = city; 12 | this.signo = this.getZodiacSign(); 13 | this.age = this.calculateAge(); 14 | this.insta = insta; 15 | this.github = github; 16 | } 17 | 18 | getZodiacSign() { 19 | let birthdate = new Date(this.birthdate); 20 | let day = birthdate.getDate(); 21 | let month = birthdate.getMonth() + 1; 22 | console.log("Passou pelo getSigno() da class User"); 23 | 24 | if ((month == 1 && day <= 20) || (month == 12 && day >= 22)) { 25 | return "Capricórnio ♑"; 26 | } else if ((month == 1 && day >= 21) || (month == 2 && day <= 18)) { 27 | return "Aquário ♒"; 28 | } else if ((month == 2 && day >= 19) || (month == 3 && day <= 20)) { 29 | return "Peixes ♓"; 30 | } else if ((month == 3 && day >= 21) || (month == 4 && day <= 20)) { 31 | return "Áries ♈"; 32 | } else if ((month == 4 && day >= 21) || (month == 5 && day <= 20)) { 33 | return "Touro ♉"; 34 | } else if ((month == 5 && day >= 21) || (month == 6 && day <= 20)) { 35 | return "Gêmeos ♊"; 36 | } else if ((month == 6 && day >= 22) || (month == 7 && day <= 22)) { 37 | return "Câncer ♋"; 38 | } else if ((month == 7 && day >= 23) || (month == 8 && day <= 23)) { 39 | return "Leão ♌"; 40 | } else if ((month == 8 && day >= 24) || (month == 9 && day <= 23)) { 41 | return "Virgem ♍"; 42 | } else if ((month == 9 && day >= 24) || (month == 10 && day <= 23)) { 43 | return "Libra ♎"; 44 | } else if ((month == 10 && day >= 24) || (month == 11 && day <= 22)) { 45 | return "Escorpião ♏"; 46 | } else if ((month == 11 && day >= 23) || (month == 12 && day <= 21)) { 47 | return "Sagitário ♐"; 48 | } 49 | } 50 | 51 | calculateAge() { 52 | let today = new Date(); 53 | let birthdate = new Date(this.birthdate); 54 | let age = today.getFullYear() - birthdate.getFullYear(); 55 | let month = today.getMonth() - birthdate.getMonth(); 56 | 57 | if (month < 0 || (month === 0 && today.getDate() < birthdate.getDate())) { 58 | age--; 59 | } 60 | console.log("Passou pelo calculateAge() da class User"); 61 | return age; 62 | 63 | } 64 | } 65 | 66 | class ListaContatos { 67 | constructor() { 68 | this.contatos = []; 69 | } 70 | 71 | adicionarContato(contato) { 72 | if(isAnyInputEmpty()){ 73 | sendMSG("Preencha todos os campos!", "error"); 74 | }else if(!isURLValida(contato.photo)){ 75 | sendMSG("URL da foto inválida!", "error"); 76 | }else if(checarIdExiste(contato.id)){ 77 | sendMSG("ID já existe!", "error"); 78 | }else{ 79 | this.contatos.push(contato); 80 | sendMSG("Contato adicionado com sucesso!", "success"); 81 | limparFormulario(); 82 | } 83 | } 84 | 85 | listarContatos() { 86 | return this.contatos; 87 | } 88 | 89 | getContactById(id) { 90 | return this.contatos.find(contato => contato.id == id); 91 | } 92 | } 93 | 94 | const listaDeContatos = new ListaContatos(); 95 | 96 | function adicionarContato() { 97 | const fullname = document.getElementById("fullname").value; 98 | const phone = document.getElementById("phone").value; 99 | const cellphone = document.getElementById("cellphone").value; 100 | const photo = document.getElementById("photo").value; 101 | const birthdate = document.getElementById("birthdate").value; 102 | const email = document.getElementById("email").value; 103 | const cep = document.getElementById("cep").value; 104 | const city = document.getElementById("city").value; 105 | const insta = document.getElementById("insta").value; 106 | const github = document.getElementById("github").value; 107 | 108 | 109 | const contato = new Contato(fullname, phone, cellphone, photo, birthdate, email, cep, city, insta, github); 110 | listaDeContatos.adicionarContato(contato); 111 | exibirContatos(); 112 | } 113 | 114 | function limparFormulario() { 115 | document.getElementById("fullname").value = ""; 116 | document.getElementById("phone").value = ""; 117 | document.getElementById("cellphone").value = ""; 118 | document.getElementById("photo").value = ""; 119 | document.getElementById("birthdate").value = ""; 120 | document.getElementById("email").value = ""; 121 | document.getElementById("cep").value = ""; 122 | document.getElementById("city").value = ""; 123 | document.getElementById("insta").value = ""; 124 | document.getElementById("github").value = ""; 125 | 126 | } 127 | 128 | function exibirContatos() { 129 | 130 | const contactList = document.getElementById("contact-list"); 131 | let html = ""; 132 | let array = listaDeContatos.listarContatos(); 133 | 134 | array.forEach(contato => { 135 | html += ` 136 |
137 | ${contato.fullname} 138 |
139 |

${contato.fullname}

140 |

Telefone Fixo: ${formateCelular(contato.phone)}

141 |

Telefone Celular: ${formateCelular(contato.cellphone)}

142 |
143 |
144 | `; 145 | }); 146 | 147 | contactList.innerHTML = html; 148 | 149 | } 150 | 151 | function isURLValida(url) { 152 | if (url.match(/\.(jpeg|jpg|gif|png)$/) != null) { 153 | return true; 154 | } else { 155 | return false; 156 | } 157 | } 158 | 159 | function sendMSG(msg, type) { 160 | const msgDiv = document.getElementById("msg"); 161 | msgDiv.innerHTML = ""; 162 | 163 | const msgP = ` 164 |

${msg}

165 | `; 166 | 167 | msgDiv.innerHTML += msgP; 168 | 169 | setTimeout(function () { 170 | msgDiv.innerHTML = ""; 171 | }, 3000); 172 | } 173 | 174 | function isAnyInputEmpty() { 175 | const fullname = document.getElementById("fullname").value; 176 | const phone = document.getElementById("phone").value; 177 | const cellphone = document.getElementById("cellphone").value; 178 | const photo = document.getElementById("photo").value; 179 | const birthdate = document.getElementById("birthdate").value; 180 | const email = document.getElementById("email").value; 181 | const cep = document.getElementById("cep").value; 182 | const city = document.getElementById("city").value; 183 | const insta = document.getElementById("insta").value; 184 | const github = document.getElementById("github").value; 185 | 186 | 187 | if(fullname == "" || phone == "" || cellphone == "" || photo == "" || birthdate == "" || email == "" || cep == "" || city == "" || insta == "" || github == ""){ 188 | return true; 189 | }else{ 190 | return false; 191 | } 192 | } 193 | 194 | function randomId() { 195 | let id = Math.floor(Math.random() * 10000); 196 | if (checarIdExiste(id) == false) { 197 | console.log("Id não existe: " + id) 198 | return id; 199 | } else { 200 | console.log("Id já existe, tente novamente") 201 | sendMSG("Id já existe, tente novamente", "error"); 202 | } 203 | } 204 | 205 | function checarIdExiste(id) { 206 | console.log("Entrou na checagem: " + id) 207 | const array = listaDeContatos.contatos; 208 | let existe = false; 209 | array.forEach(contato => { 210 | if (contato.id == id) { 211 | console.log("id existe: " + id); 212 | existe = true; 213 | } 214 | }); 215 | 216 | return existe; 217 | } 218 | 219 | function gerarLinkWhatsapp(telefone) { 220 | let link = "https://api.whatsapp.com/send?phone=55" + telefone; 221 | return link; 222 | } 223 | 224 | function gerarLinkInstagram(insta) { 225 | let link = "https://www.instagram.com/" + insta; 226 | return link; 227 | } 228 | 229 | function gerarLinkGithub(github) { 230 | let link = "https://www.github.com/" + github; 231 | return link; 232 | } 233 | 234 | function contatoDetalhe(id) { 235 | const contato = document.getElementById("recebeContato"); 236 | let html = ""; 237 | const pessoa = listaDeContatos.getContactById(id); 238 | let linkWhatsapp = gerarLinkWhatsapp(pessoa.cellphone); 239 | let linkInstagram = gerarLinkInstagram(pessoa.insta); 240 | let linkGithub = gerarLinkGithub(pessoa.github); 241 | 242 | console.log(pessoa) 243 | 244 | html += ` 245 | 273 | `; 274 | 275 | contato.innerHTML = html; 276 | 277 | exibirContatoDetalhe(); 278 | console.log(id) 279 | } 280 | 281 | function exibirContatoDetalhe() { 282 | //Tirar o display none da div card-person 283 | document.getElementById("card-person").classList.remove("hidden"); 284 | 285 | } 286 | 287 | function formateCelular(celular) { 288 | celular = celular.replace(/\D/g, ""); 289 | celular = celular.replace(/^(\d{2})(\d)/g, "($1) $2"); 290 | celular = celular.replace(/(\d)(\d{4})$/, "$1-$2"); 291 | return celular; 292 | } 293 | 294 | function formateCEP(cep) { 295 | cep = cep.replace(/\D/g, ""); 296 | cep = cep.replace(/^(\d{5})(\d)/, "$1-$2"); 297 | return cep; 298 | } 299 | 300 | function formateDataPTBR(data) { 301 | data = data.replace(/\D/g, ""); 302 | data = data.replace(/^(\d{2})(\d)/, "$1/$2"); 303 | data = data.replace(/(\d{2})(\d)/, "$1/$2"); 304 | return data; 305 | } --------------------------------------------------------------------------------