251 lines
9.4 KiB
TypeScript
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,
|
|
}
|
|
}
|