atualizacoes modulo Score e Commander

This commit is contained in:
Vitex Tecnologia
2026-05-20 10:53:17 -03:00
parent 6acfee2c76
commit 0b5c7350c5
14 changed files with 265 additions and 44 deletions
BIN
View File
Binary file not shown.
@@ -8,12 +8,26 @@ import {
ExternalLink, ExternalLink,
Landmark, Landmark,
Loader2, Loader2,
Trash2,
Wallet, Wallet,
} from "lucide-react"; } from "lucide-react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { useAuthAccess } from "@/contexts/AuthAccessContext";
import { import {
fechamentoBancoPontosService, fechamentoBancoPontosService,
type BancoPontosExtratoItem, type BancoPontosExtratoItem,
@@ -59,6 +73,8 @@ function nomeExibicaoParceiro(p: BancoPontosParceiroExtrato): string {
export default function BancoPontosExtrato() { export default function BancoPontosExtrato() {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const { me } = useAuthAccess();
const podeExcluirTransacao = me?.capabilities.bancoPontos.excluirTransacao ?? false;
const { parceiroId = "" } = useParams(); const { parceiroId = "" } = useParams();
const nomeDoState = (location.state as ExtratoLocationState | null)?.nomeExibicao?.trim(); const nomeDoState = (location.state as ExtratoLocationState | null)?.nomeExibicao?.trim();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -67,6 +83,9 @@ export default function BancoPontosExtrato() {
const [linhas, setLinhas] = useState<BancoPontosExtratoItem[]>([]); const [linhas, setLinhas] = useState<BancoPontosExtratoItem[]>([]);
const [meta, setMeta] = useState({ total: 0, paginaAtual: 1, totalPaginas: 1 }); const [meta, setMeta] = useState({ total: 0, paginaAtual: 1, totalPaginas: 1 });
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [linhaParaExcluir, setLinhaParaExcluir] = useState<BancoPontosExtratoItem | null>(null);
const [motivoExclusao, setMotivoExclusao] = useState("");
const [excluindo, setExcluindo] = useState(false);
const load = useCallback(async () => { const load = useCallback(async () => {
if (!parceiroId) return; if (!parceiroId) return;
@@ -125,6 +144,28 @@ export default function BancoPontosExtrato() {
return `Mostrando ${inicio}${fim} de ${meta.total}`; return `Mostrando ${inicio}${fim} de ${meta.total}`;
})(); })();
const handleExcluirTransacao = async () => {
if (!linhaParaExcluir) return;
const motivo = motivoExclusao.trim();
if (motivo.length < 3) {
toast.error("Informe o motivo da exclusão (mínimo 3 caracteres).");
return;
}
try {
setExcluindo(true);
await fechamentoBancoPontosService.excluirTransacao(linhaParaExcluir.id, motivo);
toast.success("Lançamento excluído do extrato.");
setLinhaParaExcluir(null);
setMotivoExclusao("");
await load();
} catch (e) {
const msg = e instanceof Error ? e.message : "Erro ao excluir lançamento.";
toast.error(msg);
} finally {
setExcluindo(false);
}
};
const handleExportarXlsx = async () => { const handleExportarXlsx = async () => {
if (!parceiroId) return; if (!parceiroId) return;
try { try {
@@ -220,19 +261,28 @@ export default function BancoPontosExtrato() {
<TableHead className="min-w-[100px]">Tipo</TableHead> <TableHead className="min-w-[100px]">Tipo</TableHead>
<TableHead className="min-w-[130px] text-right">Valor (Pontos)</TableHead> <TableHead className="min-w-[130px] text-right">Valor (Pontos)</TableHead>
<TableHead className="min-w-[120px] text-center">Fechamento</TableHead> <TableHead className="min-w-[120px] text-center">Fechamento</TableHead>
{podeExcluirTransacao ? (
<TableHead className="min-w-[80px] text-center">Ações</TableHead>
) : null}
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{loading ? ( {loading ? (
<TableRow> <TableRow>
<TableCell colSpan={6} className="py-14 text-center text-muted-foreground"> <TableCell
colSpan={podeExcluirTransacao ? 7 : 6}
className="py-14 text-center text-muted-foreground"
>
<Loader2 className="mx-auto mb-2 h-8 w-8 animate-spin text-primary" /> <Loader2 className="mx-auto mb-2 h-8 w-8 animate-spin text-primary" />
Carregando extrato... Carregando extrato...
</TableCell> </TableCell>
</TableRow> </TableRow>
) : linhasOrdenadas.length === 0 ? ( ) : linhasOrdenadas.length === 0 ? (
<TableRow> <TableRow>
<TableCell colSpan={6} className="py-12 text-center text-muted-foreground"> <TableCell
colSpan={podeExcluirTransacao ? 7 : 6}
className="py-12 text-center text-muted-foreground"
>
Nenhuma movimentação registrada para este parceiro. Nenhuma movimentação registrada para este parceiro.
</TableCell> </TableCell>
</TableRow> </TableRow>
@@ -287,6 +337,23 @@ export default function BancoPontosExtrato() {
<span className="text-sm text-muted-foreground"></span> <span className="text-sm text-muted-foreground"></span>
)} )}
</TableCell> </TableCell>
{podeExcluirTransacao ? (
<TableCell className="text-center">
<Button
type="button"
variant="ghost"
size="icon"
title="Excluir lançamento"
className="text-destructive hover:bg-destructive/10 hover:text-destructive"
onClick={() => {
setLinhaParaExcluir(linha);
setMotivoExclusao("");
}}
>
<Trash2 className="h-4 w-4" />
</Button>
</TableCell>
) : null}
</TableRow> </TableRow>
); );
}) })
@@ -330,6 +397,50 @@ export default function BancoPontosExtrato() {
</div> </div>
</div> </div>
</div> </div>
<AlertDialog
open={linhaParaExcluir != null}
onOpenChange={(open) => {
if (!open) {
setLinhaParaExcluir(null);
setMotivoExclusao("");
}
}}
>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Excluir lançamento</AlertDialogTitle>
<AlertDialogDescription>
O lançamento será removido do extrato e do saldo, mas permanece registrado no banco com motivo e
auditoria. Esta ação não pode ser desfeita pela interface.
</AlertDialogDescription>
</AlertDialogHeader>
<div className="space-y-2 py-2">
<Label htmlFor="motivo-exclusao-banco">Motivo da exclusão</Label>
<Textarea
id="motivo-exclusao-banco"
value={motivoExclusao}
onChange={(e) => setMotivoExclusao(e.target.value)}
placeholder="Descreva o motivo (mínimo 3 caracteres)"
rows={3}
disabled={excluindo}
/>
</div>
<AlertDialogFooter>
<AlertDialogCancel disabled={excluindo}>Cancelar</AlertDialogCancel>
<AlertDialogAction
disabled={excluindo || motivoExclusao.trim().length < 3}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
onClick={(e) => {
e.preventDefault();
void handleExcluirTransacao();
}}
>
{excluindo ? "Excluindo..." : "Confirmar exclusão"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div> </div>
); );
} }
@@ -356,9 +356,10 @@ export default function CompetenciaFechamentos() {
{podeImportarAsana ? ( {podeImportarAsana ? (
<Button <Button
size="sm" size="sm"
variant="secondary" variant="outline"
onClick={() => setIsReprocessModalOpen(true)} onClick={() => setIsReprocessModalOpen(true)}
disabled={importing} disabled={importing}
className="hover:bg-muted/60 hover:text-foreground"
> >
<RefreshCcw className="mr-2 h-4 w-4" /> <RefreshCcw className="mr-2 h-4 w-4" />
Reprocessar Asana Reprocessar Asana
@@ -367,7 +368,7 @@ export default function CompetenciaFechamentos() {
{podeConcluirCompetencia ? ( {podeConcluirCompetencia ? (
<Button <Button
size="sm" size="sm"
variant="outline" variant="default"
onClick={() => setIsConcluirModalOpen(true)} onClick={() => setIsConcluirModalOpen(true)}
disabled={concluindoCompetencia} disabled={concluindoCompetencia}
> >
@@ -689,8 +689,8 @@ export default function Configuracoes() {
</div> </div>
<Button <Button
type="button" type="button"
variant="secondary" variant="outline"
className="h-11 shrink-0 whitespace-nowrap px-5 lg:self-stretch" className="h-11 shrink-0 whitespace-nowrap bg-background px-5 hover:bg-muted/60 hover:text-foreground dark:bg-muted/30 dark:hover:bg-muted/50 lg:self-stretch"
onClick={handleBuscarWorkspaces} onClick={handleBuscarWorkspaces}
disabled={!podeSalvarConfig || !podeBuscarWorkspaces || Boolean(configAsanaError)} disabled={!podeSalvarConfig || !podeBuscarWorkspaces || Boolean(configAsanaError)}
> >
@@ -1076,7 +1076,7 @@ export default function FechamentoDetalhes() {
) : podeConcluirFechamento ? ( ) : podeConcluirFechamento ? (
<Button <Button
size="sm" size="sm"
variant="secondary" variant="default"
onClick={handleAbrirConcluir} onClick={handleAbrirConcluir}
disabled={tarefas.length === 0 || concluindo || isCompetenciaConcluida} disabled={tarefas.length === 0 || concluindo || isCompetenciaConcluida}
className="min-w-[152px]" className="min-w-[152px]"
@@ -1713,18 +1713,18 @@ export default function FechamentoDetalhes() {
<div className="flex flex-col gap-2 sm:flex-row sm:flex-wrap"> <div className="flex flex-col gap-2 sm:flex-row sm:flex-wrap">
<Button <Button
type="button" type="button"
variant="secondary" variant="outline"
size="sm" size="sm"
className="h-9 justify-center font-normal" className="h-9 justify-center bg-background font-normal hover:bg-muted/60 hover:text-foreground dark:bg-muted/30 dark:hover:bg-muted/50"
onClick={() => setPontuacaoPagaInput(pontuacaoTotalLabel)} onClick={() => setPontuacaoPagaInput(pontuacaoTotalLabel)}
> >
Igual aos aprovados Igual aos aprovados
</Button> </Button>
<Button <Button
type="button" type="button"
variant="secondary" variant="outline"
size="sm" size="sm"
className="h-9 justify-center font-normal" className="h-9 justify-center bg-background font-normal hover:bg-muted/60 hover:text-foreground dark:bg-muted/30 dark:hover:bg-muted/50"
onClick={() => setPontuacaoPagaInput(String(pontuacaoMeta ?? 0))} onClick={() => setPontuacaoPagaInput(String(pontuacaoMeta ?? 0))}
> >
Igual à meta Igual à meta
@@ -782,7 +782,13 @@ export default function Parceiros() {
<TableCell>{parceiro.email}</TableCell> <TableCell>{parceiro.email}</TableCell>
<TableCell>{getTipoPessoaLabel(parceiro.tipoPessoa)}</TableCell> <TableCell>{getTipoPessoaLabel(parceiro.tipoPessoa)}</TableCell>
<TableCell> <TableCell>
<Badge variant={parceiro.estaAtivo ? "secondary" : "outline"}> <Badge
className={
parceiro.estaAtivo
? "border-emerald-600/30 bg-emerald-50 font-normal text-emerald-800 hover:bg-emerald-50 dark:bg-emerald-950/40 dark:text-emerald-200"
: "border-border bg-muted/60 font-normal text-muted-foreground hover:bg-muted/60 dark:bg-muted/40 dark:text-muted-foreground"
}
>
{parceiro.estaAtivo ? "Ativo" : "Inativo"} {parceiro.estaAtivo ? "Ativo" : "Inativo"}
</Badge> </Badge>
</TableCell> </TableCell>
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { Edit, Plus, Power, Users, UserCheck, UserX } from "lucide-react"; import { Edit, Plus, Power, Trash2, Users, UserCheck, UserX } from "lucide-react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -84,6 +84,7 @@ function getEmailUsuario(usuario: UsuarioItem | null | undefined): string {
export default function Usuarios() { export default function Usuarios() {
const { me } = useAuthAccess(); const { me } = useAuthAccess();
const podeEditarUsuarios = me?.capabilities.usuarios.criarEditarToggle ?? false; const podeEditarUsuarios = me?.capabilities.usuarios.criarEditarToggle ?? false;
const podeExcluirUsuario = me?.capabilities.usuarios.excluir ?? false;
const [usuarios, setUsuarios] = useState<UsuarioItem[]>([]); const [usuarios, setUsuarios] = useState<UsuarioItem[]>([]);
const [parceiros, setParceiros] = useState<ParceiroItem[]>([]); const [parceiros, setParceiros] = useState<ParceiroItem[]>([]);
@@ -92,8 +93,10 @@ export default function Usuarios() {
const [isCreateOpen, setIsCreateOpen] = useState(false); const [isCreateOpen, setIsCreateOpen] = useState(false);
const [isEditOpen, setIsEditOpen] = useState(false); const [isEditOpen, setIsEditOpen] = useState(false);
const [isToggleOpen, setIsToggleOpen] = useState(false); const [isToggleOpen, setIsToggleOpen] = useState(false);
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [toggling, setToggling] = useState(false); const [toggling, setToggling] = useState(false);
const [deleting, setDeleting] = useState(false);
const [selectedUsuario, setSelectedUsuario] = useState<UsuarioItem | null>(null); const [selectedUsuario, setSelectedUsuario] = useState<UsuarioItem | null>(null);
const [form, setForm] = useState<UsuarioForm>(formInicial); const [form, setForm] = useState<UsuarioForm>(formInicial);
@@ -279,6 +282,30 @@ export default function Usuarios() {
} }
}; };
const openDeleteDialog = (usuario: UsuarioItem) => {
setSelectedUsuario(usuario);
setIsDeleteOpen(true);
};
const handleDeleteUsuario = async () => {
if (!selectedUsuario) {
return;
}
try {
setDeleting(true);
await fechamentoUsuariosService.excluirUsuario(selectedUsuario.id);
toast.success("Usuário excluído com sucesso.");
setIsDeleteOpen(false);
setSelectedUsuario(null);
setReloadNonce((prev) => prev + 1);
} catch (error) {
const message = error instanceof Error ? error.message : "Erro ao excluir usuário.";
toast.error(message);
} finally {
setDeleting(false);
}
};
const handleToggleStatus = async () => { const handleToggleStatus = async () => {
if (!selectedUsuario) { if (!selectedUsuario) {
return; return;
@@ -459,24 +486,40 @@ export default function Usuarios() {
</TableCell> </TableCell>
<TableCell> <TableCell>
<div className="flex items-center justify-center gap-1"> <div className="flex items-center justify-center gap-1">
{podeEditarUsuarios ? ( {podeEditarUsuarios || podeExcluirUsuario ? (
<> <>
<Button {podeEditarUsuarios ? (
variant="ghost" <>
size="icon" <Button
onClick={() => openEditDialog(usuario)} variant="ghost"
title="Editar usuário" size="icon"
> onClick={() => openEditDialog(usuario)}
<Edit className="h-4 w-4" /> title="Editar usuário"
</Button> >
<Button <Edit className="h-4 w-4" />
variant="ghost" </Button>
size="icon" <Button
onClick={() => openToggleDialog(usuario)} variant="ghost"
title={usuario.estaAtivo ? "Inativar usuário" : "Reativar usuário"} size="icon"
> onClick={() => openToggleDialog(usuario)}
<Power className="h-4 w-4" /> title={usuario.estaAtivo ? "Inativar usuário" : "Reativar usuário"}
</Button> >
<Power className="h-4 w-4" />
</Button>
</>
) : null}
{podeExcluirUsuario ? (
<Button
variant="ghost"
size="icon"
onClick={() => openDeleteDialog(usuario)}
title="Excluir usuário"
disabled={me?.id === usuario.id}
className="text-destructive hover:bg-destructive/10 hover:text-destructive"
>
<Trash2 className="h-4 w-4" />
</Button>
) : null}
</> </>
) : ( ) : (
<span className="text-xs text-muted-foreground">Somente leitura</span> <span className="text-xs text-muted-foreground">Somente leitura</span>
@@ -741,6 +784,37 @@ export default function Usuarios() {
</DialogContent> </DialogContent>
</Dialog> </Dialog>
<AlertDialog open={isDeleteOpen} onOpenChange={setIsDeleteOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Excluir usuário</AlertDialogTitle>
<AlertDialogDescription className="space-y-2">
<span className="block">
Deseja excluir o usuário <strong>{getNomeUsuario(selectedUsuario)}</strong> (
{getEmailUsuario(selectedUsuario)})?
</span>
<span className="block">
O usuário deixará de aparecer na lista e não poderá mais acessar o sistema. Se houver parceiro
vinculado, apenas o vínculo será removido os dados do parceiro e dos fechamentos permanecem
intactos.
</span>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel className="hover:bg-muted/60 hover:text-foreground" disabled={deleting}>
Cancelar
</AlertDialogCancel>
<AlertDialogAction
onClick={handleDeleteUsuario}
disabled={deleting || !selectedUsuario || me?.id === selectedUsuario?.id}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{deleting ? "Excluindo..." : "Excluir usuário"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<AlertDialog open={isToggleOpen} onOpenChange={setIsToggleOpen}> <AlertDialog open={isToggleOpen} onOpenChange={setIsToggleOpen}>
<AlertDialogContent> <AlertDialogContent>
<AlertDialogHeader> <AlertDialogHeader>
+3
View File
@@ -1,5 +1,8 @@
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
/** Operações de IA (imagem, áudio, transcrição) podem levar vários minutos. */
export const LONG_RUNNING_REQUEST_TIMEOUT_MS = 300_000;
class ApiService { class ApiService {
private readonly axiosInstance: AxiosInstance; private readonly axiosInstance: AxiosInstance;
private readonly apiKey: string; private readonly apiKey: string;
+3 -2
View File
@@ -1,5 +1,5 @@
import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions';
import { apiService } from './api'; import { apiService, LONG_RUNNING_REQUEST_TIMEOUT_MS } from './api';
export type VoiceType = 'alloy' | 'echo' | 'fable' | 'nova' | 'onyx' | 'shimmer'; export type VoiceType = 'alloy' | 'echo' | 'fable' | 'nova' | 'onyx' | 'shimmer';
@@ -135,7 +135,8 @@ class AudioGenerationService {
try { try {
const response = await apiService.post<AudioGenerationResponse>( const response = await apiService.post<AudioGenerationResponse>(
this.AUDIO_GENERATION_ENDPOINT, this.AUDIO_GENERATION_ENDPOINT,
{ estabelecimento_id: estabId, user_email: email, message, voice } { estabelecimento_id: estabId, user_email: email, message, voice },
{ timeout: LONG_RUNNING_REQUEST_TIMEOUT_MS }
); );
return response.data; return response.data;
} catch (error: unknown) { } catch (error: unknown) {
+13
View File
@@ -303,6 +303,19 @@ class FechamentoBancoPontosService {
throw error instanceof Error ? error : new Error("Erro ao exportar extrato do banco de pontos."); throw error instanceof Error ? error : new Error("Erro ao exportar extrato do banco de pontos.");
} }
} }
async excluirTransacao(transacaoId: string, motivo: string): Promise<void> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
await axios.delete(`${baseUrl}/banco-pontos/transacoes/${transacaoId}`, {
headers,
data: { motivo: motivo.trim() },
});
} catch (error) {
this.handleAxiosError(error, "Erro ao excluir lançamento do banco de pontos.");
}
}
} }
export const fechamentoBancoPontosService = new FechamentoBancoPontosService(); export const fechamentoBancoPontosService = new FechamentoBancoPontosService();
@@ -22,7 +22,7 @@ export type Capabilities = {
tarefaEditarRevisao: boolean; tarefaEditarRevisao: boolean;
tarefaExcluirManual: boolean; tarefaExcluirManual: boolean;
}; };
bancoPontos: { acessoAdmin: boolean }; bancoPontos: { acessoAdmin: boolean; excluirTransacao: boolean };
parceiros: { parceiros: {
listar: boolean; listar: boolean;
criar: boolean; criar: boolean;
@@ -31,7 +31,7 @@ export type Capabilities = {
verFator: boolean; verFator: boolean;
editarFator: boolean; editarFator: boolean;
}; };
usuarios: { listar: boolean; criarEditarToggle: boolean }; usuarios: { listar: boolean; criarEditarToggle: boolean; excluir: boolean };
configuracoes: { salvar: boolean }; configuracoes: { salvar: boolean };
}; };
@@ -57,7 +57,7 @@ function adminCapabilities(): Capabilities {
tarefaEditarRevisao: true, tarefaEditarRevisao: true,
tarefaExcluirManual: true, tarefaExcluirManual: true,
}, },
bancoPontos: { acessoAdmin: true }, bancoPontos: { acessoAdmin: true, excluirTransacao: true },
parceiros: { parceiros: {
listar: true, listar: true,
criar: true, criar: true,
@@ -66,7 +66,7 @@ function adminCapabilities(): Capabilities {
verFator: true, verFator: true,
editarFator: true, editarFator: true,
}, },
usuarios: { listar: true, criarEditarToggle: true }, usuarios: { listar: true, criarEditarToggle: true, excluir: true },
configuracoes: { salvar: true }, configuracoes: { salvar: true },
}; };
} }
@@ -93,7 +93,7 @@ function parceiroCapabilities(): Capabilities {
tarefaEditarRevisao: false, tarefaEditarRevisao: false,
tarefaExcluirManual: false, tarefaExcluirManual: false,
}, },
bancoPontos: { acessoAdmin: false }, bancoPontos: { acessoAdmin: false, excluirTransacao: false },
parceiros: { parceiros: {
listar: false, listar: false,
criar: false, criar: false,
@@ -102,7 +102,7 @@ function parceiroCapabilities(): Capabilities {
verFator: false, verFator: false,
editarFator: false, editarFator: false,
}, },
usuarios: { listar: false, criarEditarToggle: false }, usuarios: { listar: false, criarEditarToggle: false, excluir: false },
configuracoes: { salvar: false }, configuracoes: { salvar: false },
}; };
} }
@@ -129,7 +129,7 @@ function supervisorCapabilities(): Capabilities {
tarefaEditarRevisao: false, tarefaEditarRevisao: false,
tarefaExcluirManual: false, tarefaExcluirManual: false,
}, },
bancoPontos: { acessoAdmin: true }, bancoPontos: { acessoAdmin: true, excluirTransacao: false },
parceiros: { parceiros: {
listar: true, listar: true,
criar: true, criar: true,
@@ -138,7 +138,7 @@ function supervisorCapabilities(): Capabilities {
verFator: false, verFator: false,
editarFator: false, editarFator: false,
}, },
usuarios: { listar: true, criarEditarToggle: false }, usuarios: { listar: true, criarEditarToggle: false, excluir: false },
configuracoes: { salvar: false }, configuracoes: { salvar: false },
}; };
} }
+10
View File
@@ -127,6 +127,16 @@ class FechamentoUsuariosService {
this.handleAxiosError(error, "Erro ao atualizar status do usuário."); this.handleAxiosError(error, "Erro ao atualizar status do usuário.");
} }
} }
async excluirUsuario(id: string): Promise<void> {
try {
const headers = await buildCommanderHeaders();
const baseUrl = resolveCommanderBaseUrl();
await axios.delete(`${baseUrl}/usuarios/${id}`, { headers });
} catch (error) {
this.handleAxiosError(error, "Erro ao excluir usuário.");
}
}
} }
export const fechamentoUsuariosService = new FechamentoUsuariosService(); export const fechamentoUsuariosService = new FechamentoUsuariosService();
+3 -2
View File
@@ -1,5 +1,5 @@
import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions';
import { apiService } from './api'; import { apiService, LONG_RUNNING_REQUEST_TIMEOUT_MS } from './api';
export type ImageSize = '1024x1024' | '1024x1792' | '1792x1024'; export type ImageSize = '1024x1024' | '1024x1792' | '1792x1024';
@@ -127,7 +127,8 @@ class ImageGenerationService {
try { try {
const response = await apiService.post<ImageGenerationResponse>( const response = await apiService.post<ImageGenerationResponse>(
this.IMAGE_GENERATION_ENDPOINT, this.IMAGE_GENERATION_ENDPOINT,
{ estabelecimento_id: estabId, user_email: email, description, size } { estabelecimento_id: estabId, user_email: email, description, size },
{ timeout: LONG_RUNNING_REQUEST_TIMEOUT_MS }
); );
if (!response.data.success) { if (!response.data.success) {
+3 -2
View File
@@ -1,5 +1,5 @@
import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions';
import { apiService } from './api'; import { apiService, LONG_RUNNING_REQUEST_TIMEOUT_MS } from './api';
export interface TranscriptionResponse { export interface TranscriptionResponse {
success: boolean; success: boolean;
@@ -82,7 +82,8 @@ class TranscriptionService {
try { try {
const response = await apiService.postFormData<TranscriptionResponse>( const response = await apiService.postFormData<TranscriptionResponse>(
this.TRANSCRIPTION_ENDPOINT, this.TRANSCRIPTION_ENDPOINT,
formData formData,
{ timeout: LONG_RUNNING_REQUEST_TIMEOUT_MS }
); );
return response.data; return response.data;
} catch (error: unknown) { } catch (error: unknown) {