Add user
This commit is contained in:
@@ -107,6 +107,113 @@
|
|||||||
</q-tr>
|
</q-tr>
|
||||||
</template>
|
</template>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
|
<!-- Dialog para adicionar novo usuário -->
|
||||||
|
<q-dialog v-model="showNewUserDialog" persistent>
|
||||||
|
<q-card class="new-user-dialog">
|
||||||
|
<q-card-section class="new-user-dialog__header">
|
||||||
|
<div>
|
||||||
|
<h3 class="new-user-dialog__title">Adicionar Novo Usuário</h3>
|
||||||
|
<p class="new-user-dialog__subtitle">
|
||||||
|
Preencha os dados para criar um novo usuário no sistema
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<q-btn
|
||||||
|
icon="sym_o_close"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
v-close-popup
|
||||||
|
color="grey-7"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator />
|
||||||
|
|
||||||
|
<q-card-section class="new-user-dialog__form">
|
||||||
|
<TextField
|
||||||
|
v-model="newUser.nome"
|
||||||
|
label="Nome"
|
||||||
|
placeholder="Ex.: Ana"
|
||||||
|
:error="!!formErrors.nome"
|
||||||
|
:error-message="formErrors.nome"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon name="sym_o_person" color="primary" />
|
||||||
|
</template>
|
||||||
|
</TextField>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
v-model="newUser.sobrenome"
|
||||||
|
label="Sobrenome"
|
||||||
|
placeholder="Ex.: Silva"
|
||||||
|
:error="!!formErrors.sobrenome"
|
||||||
|
:error-message="formErrors.sobrenome"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon name="sym_o_person" color="primary" />
|
||||||
|
</template>
|
||||||
|
</TextField>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
v-model="newUser.email"
|
||||||
|
label="E-mail"
|
||||||
|
type="email"
|
||||||
|
placeholder="Ex.: ana.silva@clipperia.com"
|
||||||
|
:error="!!formErrors.email"
|
||||||
|
:error-message="formErrors.email"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon name="sym_o_alternate_email" color="primary" />
|
||||||
|
</template>
|
||||||
|
</TextField>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
v-model="newUser.password"
|
||||||
|
label="Senha"
|
||||||
|
:type="showPassword ? 'text' : 'password'"
|
||||||
|
placeholder="Digite uma senha segura"
|
||||||
|
:error="!!formErrors.password"
|
||||||
|
:error-message="formErrors.password"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon name="sym_o_lock" color="primary" />
|
||||||
|
</template>
|
||||||
|
<template #append>
|
||||||
|
<q-btn
|
||||||
|
:icon="
|
||||||
|
showPassword ? 'sym_o_visibility_off' : 'sym_o_visibility'
|
||||||
|
"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
@click="showPassword = !showPassword"
|
||||||
|
color="grey-7"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</TextField>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator />
|
||||||
|
|
||||||
|
<q-card-actions class="new-user-dialog__actions">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
label="Cancelar"
|
||||||
|
color="grey-7"
|
||||||
|
:disabled="submittingUser"
|
||||||
|
@click="closeNewUserDialog"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Criar Usuário"
|
||||||
|
icon="sym_o_person_add"
|
||||||
|
:loading="submittingUser"
|
||||||
|
:disabled="submittingUser"
|
||||||
|
@click="handleCreateUser"
|
||||||
|
/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -150,7 +257,7 @@ const columns = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "lastAccess",
|
name: "lastAccess",
|
||||||
label: "Último acesso",
|
label: "Criado em",
|
||||||
align: "center",
|
align: "center",
|
||||||
field: "lastAccess",
|
field: "lastAccess",
|
||||||
},
|
},
|
||||||
@@ -181,6 +288,21 @@ export default {
|
|||||||
name: "",
|
name: "",
|
||||||
email: "",
|
email: "",
|
||||||
},
|
},
|
||||||
|
showNewUserDialog: false,
|
||||||
|
showPassword: false,
|
||||||
|
submittingUser: false,
|
||||||
|
newUser: {
|
||||||
|
nome: "",
|
||||||
|
sobrenome: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
},
|
||||||
|
formErrors: {
|
||||||
|
nome: "",
|
||||||
|
sobrenome: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -213,11 +335,18 @@ export default {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("====================================");
|
this.rows = content.map((user) => ({
|
||||||
console.log(content);
|
id: user.id,
|
||||||
console.log("====================================");
|
name:
|
||||||
|
user.nome && user.sobrenome
|
||||||
|
? `${user.nome} ${user.sobrenome}`
|
||||||
|
: user.nome || user.sobrenome || "-",
|
||||||
|
email: user.email || "-",
|
||||||
|
role: this.formatRole(user.papel),
|
||||||
|
status: this.formatStatus(user.status),
|
||||||
|
lastAccess: user.criado_em || "-",
|
||||||
|
}));
|
||||||
|
|
||||||
this.rows = content;
|
|
||||||
this.pagination = {
|
this.pagination = {
|
||||||
...basePagination,
|
...basePagination,
|
||||||
...nextPagination,
|
...nextPagination,
|
||||||
@@ -245,6 +374,140 @@ export default {
|
|||||||
handleRefresh() {
|
handleRefresh() {
|
||||||
this.handleSearch({ ...this.pagination });
|
this.handleSearch({ ...this.pagination });
|
||||||
},
|
},
|
||||||
|
formatRole(role) {
|
||||||
|
const roles = {
|
||||||
|
USUARIO: "Usuário",
|
||||||
|
EDITOR: "Editor",
|
||||||
|
ADMINISTRADOR: "Administrador",
|
||||||
|
};
|
||||||
|
return roles[role] || role;
|
||||||
|
},
|
||||||
|
formatStatus(status) {
|
||||||
|
const statuses = {
|
||||||
|
PENDENTE: "Pendente",
|
||||||
|
ATIVO: "Ativo",
|
||||||
|
SUSPENSO: "Suspenso",
|
||||||
|
EXCLUIDO: "Excluído",
|
||||||
|
};
|
||||||
|
return statuses[status] || status;
|
||||||
|
},
|
||||||
|
formatDate(dateString) {
|
||||||
|
if (!dateString) return "-";
|
||||||
|
|
||||||
|
if (dateString.includes("/")) {
|
||||||
|
return dateString;
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const day = String(date.getDate()).padStart(2, "0");
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const hours = String(date.getHours()).padStart(2, "0");
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||||||
|
|
||||||
|
return `${day}/${month}/${year} ${hours}:${minutes}`;
|
||||||
|
},
|
||||||
|
handleNewUser() {
|
||||||
|
this.showNewUserDialog = true;
|
||||||
|
},
|
||||||
|
closeNewUserDialog() {
|
||||||
|
this.showNewUserDialog = false;
|
||||||
|
this.showPassword = false;
|
||||||
|
this.newUser = {
|
||||||
|
nome: "",
|
||||||
|
sobrenome: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
};
|
||||||
|
this.formErrors = {
|
||||||
|
nome: "",
|
||||||
|
sobrenome: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
validateForm() {
|
||||||
|
let isValid = true;
|
||||||
|
this.formErrors = {
|
||||||
|
nome: "",
|
||||||
|
sobrenome: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!this.newUser.nome || this.newUser.nome.trim() === "") {
|
||||||
|
this.formErrors.nome = "Nome é obrigatório";
|
||||||
|
isValid = false;
|
||||||
|
} else if (this.newUser.nome.length > 244) {
|
||||||
|
this.formErrors.nome = "Nome deve ter no máximo 244 caracteres";
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.newUser.sobrenome || this.newUser.sobrenome.trim() === "") {
|
||||||
|
this.formErrors.sobrenome = "Sobrenome é obrigatório";
|
||||||
|
isValid = false;
|
||||||
|
} else if (this.newUser.sobrenome.length > 244) {
|
||||||
|
this.formErrors.sobrenome =
|
||||||
|
"Sobrenome deve ter no máximo 244 caracteres";
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.newUser.email || this.newUser.email.trim() === "") {
|
||||||
|
this.formErrors.email = "E-mail é obrigatório";
|
||||||
|
isValid = false;
|
||||||
|
} else if (this.newUser.email.length > 244) {
|
||||||
|
this.formErrors.email = "E-mail deve ter no máximo 244 caracteres";
|
||||||
|
isValid = false;
|
||||||
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.newUser.email)) {
|
||||||
|
this.formErrors.email = "E-mail inválido";
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.newUser.password || this.newUser.password.trim() === "") {
|
||||||
|
this.formErrors.password = "Senha é obrigatória";
|
||||||
|
isValid = false;
|
||||||
|
} else if (this.newUser.password.length < 6) {
|
||||||
|
this.formErrors.password = "Senha deve ter no mínimo 6 caracteres";
|
||||||
|
isValid = false;
|
||||||
|
} else if (this.newUser.password.length > 244) {
|
||||||
|
this.formErrors.password = "Senha deve ter no máximo 244 caracteres";
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
},
|
||||||
|
async handleCreateUser() {
|
||||||
|
if (!this.validateForm()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.submittingUser = true;
|
||||||
|
|
||||||
|
await API.post("/usuarios", this.newUser);
|
||||||
|
|
||||||
|
this.$q.notify({
|
||||||
|
type: "positive",
|
||||||
|
message: "Usuário criado com sucesso!",
|
||||||
|
position: "top",
|
||||||
|
});
|
||||||
|
|
||||||
|
this.closeNewUserDialog();
|
||||||
|
this.handleSearch({ ...this.pagination, page: 1 });
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage =
|
||||||
|
error.response?.data?.message ||
|
||||||
|
"Não foi possível criar o usuário. Tente novamente.";
|
||||||
|
|
||||||
|
this.$q.notify({
|
||||||
|
type: "negative",
|
||||||
|
message: errorMessage,
|
||||||
|
position: "top",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
this.submittingUser = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -355,4 +618,77 @@ body.body--dark .users-page__cell-value {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.new-user-dialog {
|
||||||
|
min-width: 500px;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #101828;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__subtitle {
|
||||||
|
margin: 8px 0 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #475467;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.body--dark .new-user-dialog__title {
|
||||||
|
color: rgba(255, 255, 255, 0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.body--dark .new-user-dialog__subtitle {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.new-user-dialog {
|
||||||
|
min-width: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__header {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__form {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__actions {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-user-dialog__actions > * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user