Files
clube67_newwhats.local/clube67/newwhats.local/frontend/hooks/useSectorsLogic.ts
T

251 lines
9.4 KiB
TypeScript

import { useState, useCallback, useEffect } from 'react'
import { sectorApi, type Sector, type Team } from '../services/chatApiService'
// ─── State shape ──────────────────────────────────────────────────────────────
interface SectorWithTeams extends Sector {
teams: Team[]
teamsLoaded: boolean
teamsLoading: boolean
expanded: boolean
}
// ─── Hook ─────────────────────────────────────────────────────────────────────
export function useSectorsLogic() {
const [sectors, setSectors] = useState<SectorWithTeams[]>([])
const [loading, setLoading] = useState(false)
const [toast, setToast] = useState<{ message: string; type: 'success' | 'error' } | null>(null)
// ── Modal state ───────────────────────────────────────────────────────────
const [newSectorName, setNewSectorName] = useState('')
const [newSectorOpen, setNewSectorOpen] = useState(false)
const [savingSector, setSavingSector] = useState(false)
const [newTeamSectorId, setNewTeamSectorId] = useState<string | null>(null)
const [newTeamName, setNewTeamName] = useState('')
const [savingTeam, setSavingTeam] = useState(false)
const [editingSector, setEditingSector] = useState<Sector | null>(null)
const [editSectorName, setEditSectorName] = useState('')
const [savingEditSector, setSavingEditSector] = useState(false)
const [editingTeam, setEditingTeam] = useState<{ team: Team; sectorId: string } | null>(null)
const [editTeamName, setEditTeamName] = useState('')
const [savingEditTeam, setSavingEditTeam] = useState(false)
const showToast = useCallback((message: string, type: 'success' | 'error') => {
setToast({ message, type })
setTimeout(() => setToast(null), 3000)
}, [])
// ── Load sectors ──────────────────────────────────────────────────────────
const load = useCallback(async () => {
setLoading(true)
try {
const data = await sectorApi.list()
setSectors((prev) =>
data.map((s) => {
const existing = prev.find((p) => p.id === s.id)
return {
...s,
teams: existing?.teams ?? [],
teamsLoaded: existing?.teamsLoaded ?? false,
teamsLoading: false,
expanded: existing?.expanded ?? false,
}
})
)
} catch {
showToast('Erro ao carregar setores.', 'error')
} finally {
setLoading(false)
}
}, [showToast])
useEffect(() => { load() }, [])
// ── Toggle expand + load teams lazily ────────────────────────────────────
const toggleExpand = useCallback(async (sectorId: string) => {
setSectors((prev) =>
prev.map((s) =>
s.id === sectorId ? { ...s, expanded: !s.expanded } : s
)
)
// load teams if not yet loaded
const sector = sectors.find((s) => s.id === sectorId)
if (sector && !sector.teamsLoaded && !sector.teamsLoading) {
setSectors((prev) => prev.map((s) => s.id === sectorId ? { ...s, teamsLoading: true } : s))
try {
const teams = await sectorApi.listTeams(sectorId)
setSectors((prev) =>
prev.map((s) =>
s.id === sectorId ? { ...s, teams, teamsLoaded: true, teamsLoading: false } : s
)
)
} catch {
setSectors((prev) => prev.map((s) => s.id === sectorId ? { ...s, teamsLoading: false } : s))
}
}
}, [sectors])
// ── Create sector ─────────────────────────────────────────────────────────
const createSector = useCallback(async () => {
if (!newSectorName.trim()) return
setSavingSector(true)
try {
const sector = await sectorApi.create(newSectorName.trim())
setSectors((prev) => [...prev, { ...sector, teams: [], teamsLoaded: false, teamsLoading: false, expanded: false }])
setNewSectorName('')
setNewSectorOpen(false)
showToast('Setor criado.', 'success')
} catch (err: any) {
showToast(err?.response?.data?.error ?? 'Erro ao criar setor.', 'error')
} finally {
setSavingSector(false)
}
}, [newSectorName, showToast])
// ── Edit sector ───────────────────────────────────────────────────────────
const openEditSector = useCallback((sector: Sector) => {
setEditingSector(sector)
setEditSectorName(sector.name)
}, [])
const saveEditSector = useCallback(async () => {
if (!editingSector) return
setSavingEditSector(true)
try {
const updated = await sectorApi.update(editingSector.id, { name: editSectorName.trim() })
setSectors((prev) => prev.map((s) => s.id === updated.id ? { ...s, ...updated } : s))
setEditingSector(null)
showToast('Setor atualizado.', 'success')
} catch (err: any) {
showToast(err?.response?.data?.error ?? 'Erro ao atualizar setor.', 'error')
} finally {
setSavingEditSector(false)
}
}, [editingSector, editSectorName, showToast])
const toggleSectorActive = useCallback(async (sector: Sector) => {
try {
const updated = await sectorApi.update(sector.id, { isActive: !sector.isActive })
setSectors((prev) => prev.map((s) => s.id === updated.id ? { ...s, ...updated } : s))
} catch {
showToast('Erro ao alterar status.', 'error')
}
}, [showToast])
const deleteSector = useCallback(async (sectorId: string) => {
try {
await sectorApi.delete(sectorId)
setSectors((prev) => prev.filter((s) => s.id !== sectorId))
showToast('Setor removido.', 'success')
} catch {
showToast('Erro ao remover setor.', 'error')
}
}, [showToast])
// ── Create team ───────────────────────────────────────────────────────────
const openNewTeam = useCallback((sectorId: string) => {
setNewTeamSectorId(sectorId)
setNewTeamName('')
}, [])
const createTeam = useCallback(async () => {
if (!newTeamSectorId || !newTeamName.trim()) return
setSavingTeam(true)
try {
const team = await sectorApi.createTeam(newTeamSectorId, newTeamName.trim())
setSectors((prev) =>
prev.map((s) =>
s.id === newTeamSectorId
? { ...s, teams: [...s.teams, team], teamsLoaded: true }
: s
)
)
setNewTeamSectorId(null)
setNewTeamName('')
showToast('Equipe criada.', 'success')
} catch (err: any) {
showToast(err?.response?.data?.error ?? 'Erro ao criar equipe.', 'error')
} finally {
setSavingTeam(false)
}
}, [newTeamSectorId, newTeamName, showToast])
// ── Edit team ─────────────────────────────────────────────────────────────
const openEditTeam = useCallback((team: Team, sectorId: string) => {
setEditingTeam({ team, sectorId })
setEditTeamName(team.name)
}, [])
const saveEditTeam = useCallback(async () => {
if (!editingTeam) return
setSavingEditTeam(true)
try {
const updated = await sectorApi.updateTeam(editingTeam.sectorId, editingTeam.team.id, { name: editTeamName.trim() })
setSectors((prev) =>
prev.map((s) =>
s.id === editingTeam.sectorId
? { ...s, teams: s.teams.map((t) => t.id === updated.id ? updated : t) }
: s
)
)
setEditingTeam(null)
showToast('Equipe atualizada.', 'success')
} catch (err: any) {
showToast(err?.response?.data?.error ?? 'Erro ao atualizar equipe.', 'error')
} finally {
setSavingEditTeam(false)
}
}, [editingTeam, editTeamName, showToast])
const deleteTeam = useCallback(async (sectorId: string, teamId: string) => {
try {
await sectorApi.deleteTeam(sectorId, teamId)
setSectors((prev) =>
prev.map((s) =>
s.id === sectorId ? { ...s, teams: s.teams.filter((t) => t.id !== teamId) } : s
)
)
showToast('Equipe removida.', 'success')
} catch {
showToast('Erro ao remover equipe.', 'error')
}
}, [showToast])
return {
sectors, loading, load,
// sector create
newSectorName, setNewSectorName,
newSectorOpen, setNewSectorOpen,
savingSector, createSector,
// sector edit
editingSector, editSectorName, setEditSectorName,
savingEditSector, openEditSector, saveEditSector,
setEditingSector,
// sector actions
toggleSectorActive, deleteSector, toggleExpand,
// team create
newTeamSectorId, newTeamName, setNewTeamName,
savingTeam, openNewTeam, createTeam,
setNewTeamSectorId,
// team edit
editingTeam, editTeamName, setEditTeamName,
savingEditTeam, openEditTeam, saveEditTeam,
setEditingTeam,
// team actions
deleteTeam,
toast,
}
}