Auto-open modals from global quick actions
This commit is contained in:
parent
59a94744b3
commit
abb29d9116
7 changed files with 70 additions and 11 deletions
|
|
@ -8,9 +8,13 @@ import { fetchCompaniesByTenant, normalizeCompany } from "@/server/company-servi
|
||||||
export const runtime = "nodejs"
|
export const runtime = "nodejs"
|
||||||
export const dynamic = "force-dynamic"
|
export const dynamic = "force-dynamic"
|
||||||
|
|
||||||
export default async function AdminCompaniesPage() {
|
export default async function AdminCompaniesPage({
|
||||||
|
searchParams,
|
||||||
|
}: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {
|
||||||
const session = await requireStaffSession()
|
const session = await requireStaffSession()
|
||||||
const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
||||||
|
const params = await searchParams
|
||||||
|
const autoOpenCreateCompany = params.quick === "new-company"
|
||||||
const companies = (await fetchCompaniesByTenant(tenantId)).map(normalizeCompany)
|
const companies = (await fetchCompaniesByTenant(tenantId)).map(normalizeCompany)
|
||||||
return (
|
return (
|
||||||
<AppShell
|
<AppShell
|
||||||
|
|
@ -19,7 +23,11 @@ export default async function AdminCompaniesPage() {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="mx-auto w-full max-w-7xl px-4 md:px-8 lg:px-10">
|
<div className="mx-auto w-full max-w-7xl px-4 md:px-8 lg:px-10">
|
||||||
<AdminCompaniesManager initialCompanies={companies} tenantId={tenantId} />
|
<AdminCompaniesManager
|
||||||
|
initialCompanies={companies}
|
||||||
|
tenantId={tenantId}
|
||||||
|
autoOpenCreate={autoOpenCreateCompany}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</AppShell>
|
</AppShell>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export default async function AdminDevicesPage({
|
||||||
const params = await searchParams
|
const params = await searchParams
|
||||||
const companyParam = params.company
|
const companyParam = params.company
|
||||||
const company = typeof companyParam === "string" ? companyParam : undefined
|
const company = typeof companyParam === "string" ? companyParam : undefined
|
||||||
|
const autoOpenCreateDevice = params.quick === "new-device"
|
||||||
return (
|
return (
|
||||||
<AppShell
|
<AppShell
|
||||||
header={
|
header={
|
||||||
|
|
@ -22,7 +23,11 @@ export default async function AdminDevicesPage({
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="mx-auto w-full max-w-6xl px-4 pb-12 lg:px-6">
|
<div className="mx-auto w-full max-w-6xl px-4 pb-12 lg:px-6">
|
||||||
<AdminDevicesOverview tenantId={DEFAULT_TENANT_ID} initialCompanyFilterSlug={company ?? "all"} />
|
<AdminDevicesOverview
|
||||||
|
tenantId={DEFAULT_TENANT_ID}
|
||||||
|
initialCompanyFilterSlug={company ?? "all"}
|
||||||
|
autoOpenCreateDevice={autoOpenCreateDevice}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</AppShell>
|
</AppShell>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,13 @@ import { fetchCompaniesByTenant, normalizeCompany } from "@/server/company-servi
|
||||||
export const runtime = "nodejs"
|
export const runtime = "nodejs"
|
||||||
export const dynamic = "force-dynamic"
|
export const dynamic = "force-dynamic"
|
||||||
|
|
||||||
export default async function AdminUsersPage() {
|
export default async function AdminUsersPage({
|
||||||
|
searchParams,
|
||||||
|
}: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {
|
||||||
const session = await requireStaffSession()
|
const session = await requireStaffSession()
|
||||||
const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
||||||
|
const params = await searchParams
|
||||||
|
const autoOpenCreateUser = params.quick === "new-user"
|
||||||
|
|
||||||
const users = await prisma.user.findMany({
|
const users = await prisma.user.findMany({
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -103,7 +107,12 @@ export default async function AdminUsersPage() {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="mx-auto w-full max-w-7xl px-4 pb-12 lg:px-8">
|
<div className="mx-auto w-full max-w-7xl px-4 pb-12 lg:px-8">
|
||||||
<AdminUsersWorkspace initialAccounts={accounts} companies={companies} tenantId={tenantId} />
|
<AdminUsersWorkspace
|
||||||
|
initialAccounts={accounts}
|
||||||
|
companies={companies}
|
||||||
|
tenantId={tenantId}
|
||||||
|
autoOpenCreate={autoOpenCreateUser}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</AppShell>
|
</AppShell>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ type LastAlertInfo = { createdAt: number; usagePct: number; threshold: number }
|
||||||
type Props = {
|
type Props = {
|
||||||
initialCompanies: NormalizedCompany[]
|
initialCompanies: NormalizedCompany[]
|
||||||
tenantId?: string | null
|
tenantId?: string | null
|
||||||
|
autoOpenCreate?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type ViewMode = "table" | "board"
|
type ViewMode = "table" | "board"
|
||||||
|
|
@ -291,7 +292,7 @@ function FieldError({ error }: { error?: string }) {
|
||||||
return <p className="text-xs font-medium text-destructive">{error}</p>
|
return <p className="text-xs font-medium text-destructive">{error}</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminCompaniesManager({ initialCompanies, tenantId }: Props) {
|
export function AdminCompaniesManager({ initialCompanies, tenantId, autoOpenCreate = false }: Props) {
|
||||||
const [companies, setCompanies] = useState<NormalizedCompany[]>(() => initialCompanies)
|
const [companies, setCompanies] = useState<NormalizedCompany[]>(() => initialCompanies)
|
||||||
const [view, setView] = useState<ViewMode>("table")
|
const [view, setView] = useState<ViewMode>("table")
|
||||||
const [search, setSearch] = useState("")
|
const [search, setSearch] = useState("")
|
||||||
|
|
@ -429,6 +430,12 @@ export function AdminCompaniesManager({ initialCompanies, tenantId }: Props) {
|
||||||
|
|
||||||
const cancelDelete = useCallback(() => setIsDeleting(null), [])
|
const cancelDelete = useCallback(() => setIsDeleting(null), [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoOpenCreate) {
|
||||||
|
openCreate()
|
||||||
|
}
|
||||||
|
}, [autoOpenCreate, openCreate])
|
||||||
|
|
||||||
const handleDelete = useCallback(async () => {
|
const handleDelete = useCallback(async () => {
|
||||||
if (!isDeleting) return
|
if (!isDeleting) return
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1268,7 +1268,15 @@ function OsIcon({ osName }: { osName?: string | null }) {
|
||||||
return <Monitor className="size-4 text-black" />
|
return <Monitor className="size-4 text-black" />
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all" }: { tenantId: string; initialCompanyFilterSlug?: string }) {
|
export function AdminDevicesOverview({
|
||||||
|
tenantId,
|
||||||
|
initialCompanyFilterSlug = "all",
|
||||||
|
autoOpenCreateDevice = false,
|
||||||
|
}: {
|
||||||
|
tenantId: string
|
||||||
|
initialCompanyFilterSlug?: string
|
||||||
|
autoOpenCreateDevice?: boolean
|
||||||
|
}) {
|
||||||
const { devices, isLoading } = useDevicesQuery(tenantId)
|
const { devices, isLoading } = useDevicesQuery(tenantId)
|
||||||
const [q, setQ] = useState("")
|
const [q, setQ] = useState("")
|
||||||
const [statusFilter, setStatusFilter] = useState<string>("all")
|
const [statusFilter, setStatusFilter] = useState<string>("all")
|
||||||
|
|
@ -1555,6 +1563,12 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
|
||||||
setIsCreateDeviceOpen(true)
|
setIsCreateDeviceOpen(true)
|
||||||
}, [selectedCompany, companyFilterSlug])
|
}, [selectedCompany, companyFilterSlug])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoOpenCreateDevice) {
|
||||||
|
handleOpenCreateDevice()
|
||||||
|
}
|
||||||
|
}, [autoOpenCreateDevice, handleOpenCreateDevice])
|
||||||
|
|
||||||
const handleCreateDevice = useCallback(async () => {
|
const handleCreateDevice = useCallback(async () => {
|
||||||
if (!convexUserId) {
|
if (!convexUserId) {
|
||||||
toast.error("Sincronize a sessão antes de criar dispositivos.")
|
toast.error("Sincronize a sessão antes de criar dispositivos.")
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ type Props = {
|
||||||
initialAccounts: AdminAccount[]
|
initialAccounts: AdminAccount[]
|
||||||
companies: NormalizedCompany[]
|
companies: NormalizedCompany[]
|
||||||
tenantId: string
|
tenantId: string
|
||||||
|
autoOpenCreate?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type SectionEditorState =
|
type SectionEditorState =
|
||||||
|
|
@ -164,7 +165,7 @@ function FieldError({ message }: { message?: string }) {
|
||||||
return <p className="text-xs font-medium text-destructive">{message}</p>
|
return <p className="text-xs font-medium text-destructive">{message}</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminUsersWorkspace({ initialAccounts, companies, tenantId }: Props) {
|
export function AdminUsersWorkspace({ initialAccounts, companies, tenantId, autoOpenCreate = false }: Props) {
|
||||||
const [tab, setTab] = useState<"accounts" | "structure">("accounts")
|
const [tab, setTab] = useState<"accounts" | "structure">("accounts")
|
||||||
return (
|
return (
|
||||||
<Tabs value={tab} onValueChange={(value) => setTab(value as typeof tab)}>
|
<Tabs value={tab} onValueChange={(value) => setTab(value as typeof tab)}>
|
||||||
|
|
@ -173,7 +174,12 @@ export function AdminUsersWorkspace({ initialAccounts, companies, tenantId }: Pr
|
||||||
<TabsTrigger value="structure">Estrutura das empresas</TabsTrigger>
|
<TabsTrigger value="structure">Estrutura das empresas</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="accounts">
|
<TabsContent value="accounts">
|
||||||
<AccountsTable initialAccounts={initialAccounts} companies={companies} tenantId={tenantId} />
|
<AccountsTable
|
||||||
|
initialAccounts={initialAccounts}
|
||||||
|
companies={companies}
|
||||||
|
tenantId={tenantId}
|
||||||
|
autoOpenCreate={autoOpenCreate}
|
||||||
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="structure">
|
<TabsContent value="structure">
|
||||||
<CompanyStructurePanel initialCompanies={companies} />
|
<CompanyStructurePanel initialCompanies={companies} />
|
||||||
|
|
@ -186,10 +192,12 @@ function AccountsTable({
|
||||||
initialAccounts,
|
initialAccounts,
|
||||||
companies,
|
companies,
|
||||||
tenantId,
|
tenantId,
|
||||||
|
autoOpenCreate,
|
||||||
}: {
|
}: {
|
||||||
initialAccounts: AdminAccount[]
|
initialAccounts: AdminAccount[]
|
||||||
companies: NormalizedCompany[]
|
companies: NormalizedCompany[]
|
||||||
tenantId: string
|
tenantId: string
|
||||||
|
autoOpenCreate?: boolean
|
||||||
}) {
|
}) {
|
||||||
const [accounts, setAccounts] = useState(initialAccounts)
|
const [accounts, setAccounts] = useState(initialAccounts)
|
||||||
const [search, setSearch] = useState("")
|
const [search, setSearch] = useState("")
|
||||||
|
|
@ -212,6 +220,7 @@ function AccountsTable({
|
||||||
const [isResettingPassword, setIsResettingPassword] = useState(false)
|
const [isResettingPassword, setIsResettingPassword] = useState(false)
|
||||||
const [passwordPreview, setPasswordPreview] = useState<string | null>(null)
|
const [passwordPreview, setPasswordPreview] = useState<string | null>(null)
|
||||||
const [createDialogOpen, setCreateDialogOpen] = useState(false)
|
const [createDialogOpen, setCreateDialogOpen] = useState(false)
|
||||||
|
const autoOpenHandledRef = useRef(false)
|
||||||
const [isCreatingAccount, setIsCreatingAccount] = useState(false)
|
const [isCreatingAccount, setIsCreatingAccount] = useState(false)
|
||||||
const [createForm, setCreateForm] = useState<CreateAccountFormState>(() => createDefaultAccountForm())
|
const [createForm, setCreateForm] = useState<CreateAccountFormState>(() => createDefaultAccountForm())
|
||||||
|
|
||||||
|
|
@ -400,6 +409,13 @@ function AccountsTable({
|
||||||
setCreateForm(createDefaultAccountForm())
|
setCreateForm(createDefaultAccountForm())
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!autoOpenCreate || autoOpenHandledRef.current) return
|
||||||
|
autoOpenHandledRef.current = true
|
||||||
|
setCreateForm(createDefaultAccountForm())
|
||||||
|
setCreateDialogOpen(true)
|
||||||
|
}, [autoOpenCreate])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editAccount) {
|
if (editAccount) {
|
||||||
setEditForm({
|
setEditForm({
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export function GlobalQuickActions() {
|
||||||
label: "Adicionar empresa",
|
label: "Adicionar empresa",
|
||||||
description: "Cadastrar novo cliente",
|
description: "Cadastrar novo cliente",
|
||||||
icon: Building,
|
icon: Building,
|
||||||
href: "/admin/companies",
|
href: "/admin/companies?quick=new-company",
|
||||||
visible: Boolean(isAdmin),
|
visible: Boolean(isAdmin),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -47,7 +47,7 @@ export function GlobalQuickActions() {
|
||||||
label: "Novo usuário",
|
label: "Novo usuário",
|
||||||
description: "Gestores / colaboradores",
|
description: "Gestores / colaboradores",
|
||||||
icon: UserPlus,
|
icon: UserPlus,
|
||||||
href: "/admin/users",
|
href: "/admin/users?quick=new-user",
|
||||||
visible: Boolean(isAdmin),
|
visible: Boolean(isAdmin),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue