página de usuário
This commit is contained in:
1 parent
110a762ff9
commit
29645f3fde
9 files changed
+6975
-16
No files matched your search
+281
@@ -0,0 +1,281 @@
|
||||
---
|
||||
layout: default
|
||||
title: Meu Perfil - MMPSearch
|
||||
permalink: /perfil/
|
||||
---
|
||||
|
||||
<main class="main-content">
|
||||
<div class="publication">
|
||||
<div class="container">
|
||||
<br />
|
||||
|
||||
<div class="tabs is-centered is-boxed is-medium mb-6">
|
||||
{% include sidebar.html %}
|
||||
</div>
|
||||
|
||||
<div class="box p-0" style="overflow: hidden; border-radius: 12px; position: relative;">
|
||||
<div id="cover-container" style="height: 200px; background-color: #ddd; background-size: cover; background-position: center; position: relative;">
|
||||
<button class="button is-small is-white is-rounded" style="position: absolute; top: 10px; right: 10px; opacity: 0.8;" onclick="document.getElementById('cover-input').click()">
|
||||
<i class="fa-solid fa-camera mr-1"></i> Alterar Capa
|
||||
</button>
|
||||
<input type="file" id="cover-input" class="is-hidden" accept="image/*">
|
||||
</div>
|
||||
|
||||
<div class="p-5" style="position: relative;">
|
||||
<div style="position: absolute; top: -60px; left: 30px;">
|
||||
<figure class="image is-128x128">
|
||||
<img id="avatar-img" class="is-rounded" src="https://bulma.io/images/placeholders/128x128.png" style="border: 4px solid white; background: white; object-fit: cover;">
|
||||
</figure>
|
||||
<button class="button is-small is-rounded is-light" style="position: absolute; bottom: 0; right: 0;" onclick="document.getElementById('avatar-input').click()">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</button>
|
||||
<input type="file" id="avatar-input" class="is-hidden" accept="image/*">
|
||||
</div>
|
||||
|
||||
<div class="columns" style="margin-top: 50px;">
|
||||
<div class="column is-8">
|
||||
<h1 class="title is-3" id="display-username">Carregando...</h1>
|
||||
|
||||
<p class="subtitle is-6 has-text-grey" id="display-bio">...</p>
|
||||
|
||||
<div class="tags mt-3" id="display-tags">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-4 has-text-right">
|
||||
<button class="button is-info is-outlined" id="btn-edit-profile">
|
||||
<i class="fa-solid fa-edit mr-2"></i> Editar Perfil
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="edit-form-box" class="box is-hidden has-background-light">
|
||||
<h3 class="title is-5"><i class="fa-solid fa-user-cog"></i> Editar Informações</h3>
|
||||
<form id="profile-form">
|
||||
<div class="field">
|
||||
<label class="label">Nome de Usuário</label>
|
||||
<div class="control has-icons-left">
|
||||
<input class="input" type="text" name="username" id="input-username" required>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-user"></i></span>
|
||||
</div>
|
||||
<p class="help">Alterar seu nome pode quebrar links antigos.</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Bio (Max 240)</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" name="bio" id="input-bio" maxlength="240" rows="2"></textarea>
|
||||
</div>
|
||||
<p class="help has-text-right" id="char-count">0/240</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Tags (separadas por vírgula)</label>
|
||||
<div class="control has-icons-left">
|
||||
<input class="input" type="text" name="tags" id="input-tags" placeholder="Ex: Trap, Dark, Samples, LMMS">
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-hashtag"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button type="submit" class="button is-success">Salvar Alterações</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button type="button" class="button is-light" id="btn-cancel-edit">Cancelar</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="update-msg" class="notification is-hidden mt-2"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="box mt-5">
|
||||
<div class="tabs is-boxed">
|
||||
<ul>
|
||||
<li class="is-active" data-tab="projects-tab"><a><span class="icon"><i class="fa-solid fa-folder"></i></span> <span>Projetos</span></a></li>
|
||||
<li data-tab="samples-tab"><a><span class="icon"><i class="fa-solid fa-music"></i></span> <span>Samples</span></a></li>
|
||||
<li data-tab="recordings-tab"><a><span class="icon"><i class="fa-solid fa-microphone"></i></span> <span>Gravações</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="projects-tab" class="content-tab-content">
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<thead><tr><th>Nome</th><th>Data</th><th>Ações</th></tr></thead>
|
||||
<tbody id="projects-list">
|
||||
</tbody>
|
||||
</table>
|
||||
<p id="no-projects" class="has-text-grey is-hidden has-text-centered p-4">Nenhum projeto encontrado.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="samples-tab" class="content-tab-content is-hidden">
|
||||
<p class="has-text-centered has-text-grey p-5">Funcionalidade de Samples em desenvolvimento.</p>
|
||||
</div>
|
||||
|
||||
<div id="recordings-tab" class="content-tab-content is-hidden">
|
||||
<p class="has-text-centered has-text-grey p-5">Funcionalidade de Gravações em desenvolvimento.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Referências do DOM
|
||||
const els = {
|
||||
username: document.getElementById('display-username'),
|
||||
bio: document.getElementById('display-bio'),
|
||||
tags: document.getElementById('display-tags'),
|
||||
avatar: document.getElementById('avatar-img'),
|
||||
cover: document.getElementById('cover-container'),
|
||||
|
||||
formBox: document.getElementById('edit-form-box'),
|
||||
form: document.getElementById('profile-form'),
|
||||
inpUser: document.getElementById('input-username'),
|
||||
inpBio: document.getElementById('input-bio'),
|
||||
inpTags: document.getElementById('input-tags'),
|
||||
msg: document.getElementById('update-msg'),
|
||||
|
||||
btnEdit: document.getElementById('btn-edit-profile'),
|
||||
btnCancel: document.getElementById('btn-cancel-edit'),
|
||||
|
||||
projectList: document.getElementById('projects-list')
|
||||
};
|
||||
|
||||
// 1. Carregar Perfil
|
||||
async function loadProfile() {
|
||||
try {
|
||||
const res = await fetch('/api/user/profile');
|
||||
if (res.status === 401) window.location.href = '/login/';
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// Preencher UI
|
||||
els.username.textContent = data.username;
|
||||
els.bio.textContent = data.bio || "Sem bio definida.";
|
||||
|
||||
// Preencher Tags
|
||||
els.tags.innerHTML = '';
|
||||
if(data.tags){
|
||||
data.tags.split(',').forEach(tag => {
|
||||
if(tag.trim()) {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'tag is-info is-light mr-1';
|
||||
span.textContent = tag.trim();
|
||||
els.tags.appendChild(span);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Preencher Inputs do Form
|
||||
els.inpUser.value = data.username;
|
||||
els.inpBio.value = data.bio || "";
|
||||
els.inpTags.value = data.tags || "";
|
||||
|
||||
// Imagens (Se tiver implementado URL no back)
|
||||
// els.avatar.src = data.avatar;
|
||||
// els.cover.style.backgroundImage = `url('${data.cover}')`;
|
||||
|
||||
// Listar Projetos
|
||||
els.projectList.innerHTML = '';
|
||||
if (data.projects && data.projects.length > 0) {
|
||||
data.projects.forEach(p => {
|
||||
els.projectList.innerHTML += `
|
||||
<tr>
|
||||
<td><strong>${p.display_name}</strong></td>
|
||||
<td>${p.created_at}</td>
|
||||
<td>
|
||||
<a href="${p.download_link}" class="button is-small is-primary is-outlined">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</a>
|
||||
<button class="button is-small is-danger is-outlined" onclick="deleteProject(${p.id})">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
} else {
|
||||
document.getElementById('no-projects').classList.remove('is-hidden');
|
||||
}
|
||||
|
||||
} catch(e) { console.error("Erro ao carregar perfil", e); }
|
||||
}
|
||||
|
||||
loadProfile();
|
||||
|
||||
// 2. Lógica de Abas
|
||||
document.querySelectorAll('.tabs li').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
document.querySelectorAll('.tabs li').forEach(t => t.classList.remove('is-active'));
|
||||
tab.classList.add('is-active');
|
||||
|
||||
document.querySelectorAll('.content-tab-content').forEach(c => c.classList.add('is-hidden'));
|
||||
document.getElementById(tab.dataset.tab).classList.remove('is-hidden');
|
||||
});
|
||||
});
|
||||
|
||||
// 3. Editar Perfil (Toggle)
|
||||
els.btnEdit.onclick = () => els.formBox.classList.remove('is-hidden');
|
||||
els.btnCancel.onclick = () => els.formBox.classList.add('is-hidden');
|
||||
|
||||
// 4. Salvar Alterações
|
||||
els.form.onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
els.msg.classList.add('is-hidden');
|
||||
|
||||
const payload = {
|
||||
username: els.inpUser.value,
|
||||
bio: els.inpBio.value,
|
||||
tags: els.inpTags.value
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/user/update', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
els.msg.textContent = data.message || data.error;
|
||||
els.msg.classList.remove('is-hidden');
|
||||
|
||||
if(res.ok) {
|
||||
els.msg.className = "notification is-success mt-2";
|
||||
setTimeout(() => {
|
||||
els.formBox.classList.add('is-hidden');
|
||||
loadProfile(); // Recarrega os dados na tela
|
||||
}, 1000);
|
||||
} else {
|
||||
els.msg.className = "notification is-danger mt-2";
|
||||
}
|
||||
} catch(err) {
|
||||
els.msg.textContent = "Erro de conexão";
|
||||
els.msg.className = "notification is-danger mt-2";
|
||||
els.msg.classList.remove('is-hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// Contador de Caracteres da Bio
|
||||
els.inpBio.addEventListener('input', function() {
|
||||
document.getElementById('char-count').textContent = `${this.value.length}/240`;
|
||||
});
|
||||
|
||||
// Função Global para Deletar (opcional)
|
||||
window.deleteProject = async (id) => {
|
||||
if(!confirm("Tem certeza que deseja apagar este projeto?")) return;
|
||||
try {
|
||||
const res = await fetch(`/api/project/${id}`, { method: 'DELETE' });
|
||||
if(res.ok) loadProfile();
|
||||
else alert("Erro ao apagar");
|
||||
} catch(e) { alert("Erro de conexão"); }
|
||||
};
|
||||
});
|
||||
</script>
|
||||
Reference in new issue
Block a user