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 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 tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
||||
const params = await searchParams
|
||||
const autoOpenCreateCompany = params.quick === "new-company"
|
||||
const companies = (await fetchCompaniesByTenant(tenantId)).map(normalizeCompany)
|
||||
return (
|
||||
<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">
|
||||
<AdminCompaniesManager initialCompanies={companies} tenantId={tenantId} />
|
||||
<AdminCompaniesManager
|
||||
initialCompanies={companies}
|
||||
tenantId={tenantId}
|
||||
autoOpenCreate={autoOpenCreateCompany}
|
||||
/>
|
||||
</div>
|
||||
</AppShell>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export default async function AdminDevicesPage({
|
|||
const params = await searchParams
|
||||
const companyParam = params.company
|
||||
const company = typeof companyParam === "string" ? companyParam : undefined
|
||||
const autoOpenCreateDevice = params.quick === "new-device"
|
||||
return (
|
||||
<AppShell
|
||||
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">
|
||||
<AdminDevicesOverview tenantId={DEFAULT_TENANT_ID} initialCompanyFilterSlug={company ?? "all"} />
|
||||
<AdminDevicesOverview
|
||||
tenantId={DEFAULT_TENANT_ID}
|
||||
initialCompanyFilterSlug={company ?? "all"}
|
||||
autoOpenCreateDevice={autoOpenCreateDevice}
|
||||
/>
|
||||
</div>
|
||||
</AppShell>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@ import { fetchCompaniesByTenant, normalizeCompany } from "@/server/company-servi
|
|||
export const runtime = "nodejs"
|
||||
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 tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
||||
const params = await searchParams
|
||||
const autoOpenCreateUser = params.quick === "new-user"
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
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">
|
||||
<AdminUsersWorkspace initialAccounts={accounts} companies={companies} tenantId={tenantId} />
|
||||
<AdminUsersWorkspace
|
||||
initialAccounts={accounts}
|
||||
companies={companies}
|
||||
tenantId={tenantId}
|
||||
autoOpenCreate={autoOpenCreateUser}
|
||||
/>
|
||||
</div>
|
||||
</AppShell>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ type LastAlertInfo = { createdAt: number; usagePct: number; threshold: number }
|
|||
type Props = {
|
||||
initialCompanies: NormalizedCompany[]
|
||||
tenantId?: string | null
|
||||
autoOpenCreate?: boolean
|
||||
}
|
||||
|
||||
type ViewMode = "table" | "board"
|
||||
|
|
@ -291,7 +292,7 @@ function FieldError({ error }: { error?: string }) {
|
|||
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 [view, setView] = useState<ViewMode>("table")
|
||||
const [search, setSearch] = useState("")
|
||||
|
|
@ -429,6 +430,12 @@ export function AdminCompaniesManager({ initialCompanies, tenantId }: Props) {
|
|||
|
||||
const cancelDelete = useCallback(() => setIsDeleting(null), [])
|
||||
|
||||
useEffect(() => {
|
||||
if (autoOpenCreate) {
|
||||
openCreate()
|
||||
}
|
||||
}, [autoOpenCreate, openCreate])
|
||||
|
||||
const handleDelete = useCallback(async () => {
|
||||
if (!isDeleting) return
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1268,7 +1268,15 @@ function OsIcon({ osName }: { osName?: string | null }) {
|
|||
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 [q, setQ] = useState("")
|
||||
const [statusFilter, setStatusFilter] = useState<string>("all")
|
||||
|
|
@ -1555,6 +1563,12 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
|
|||
setIsCreateDeviceOpen(true)
|
||||
}, [selectedCompany, companyFilterSlug])
|
||||
|
||||
useEffect(() => {
|
||||
if (autoOpenCreateDevice) {
|
||||
handleOpenCreateDevice()
|
||||
}
|
||||
}, [autoOpenCreateDevice, handleOpenCreateDevice])
|
||||
|
||||
const handleCreateDevice = useCallback(async () => {
|
||||
if (!convexUserId) {
|
||||
toast.error("Sincronize a sessão antes de criar dispositivos.")
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ type Props = {
|
|||
initialAccounts: AdminAccount[]
|
||||
companies: NormalizedCompany[]
|
||||
tenantId: string
|
||||
autoOpenCreate?: boolean
|
||||
}
|
||||
|
||||
type SectionEditorState =
|
||||
|
|
@ -164,7 +165,7 @@ function FieldError({ message }: { message?: string }) {
|
|||
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")
|
||||
return (
|
||||
<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>
|
||||
</TabsList>
|
||||
<TabsContent value="accounts">
|
||||
<AccountsTable initialAccounts={initialAccounts} companies={companies} tenantId={tenantId} />
|
||||
<AccountsTable
|
||||
initialAccounts={initialAccounts}
|
||||
companies={companies}
|
||||
tenantId={tenantId}
|
||||
autoOpenCreate={autoOpenCreate}
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="structure">
|
||||
<CompanyStructurePanel initialCompanies={companies} />
|
||||
|
|
@ -186,10 +192,12 @@ function AccountsTable({
|
|||
initialAccounts,
|
||||
companies,
|
||||
tenantId,
|
||||
autoOpenCreate,
|
||||
}: {
|
||||
initialAccounts: AdminAccount[]
|
||||
companies: NormalizedCompany[]
|
||||
tenantId: string
|
||||
autoOpenCreate?: boolean
|
||||
}) {
|
||||
const [accounts, setAccounts] = useState(initialAccounts)
|
||||
const [search, setSearch] = useState("")
|
||||
|
|
@ -212,6 +220,7 @@ function AccountsTable({
|
|||
const [isResettingPassword, setIsResettingPassword] = useState(false)
|
||||
const [passwordPreview, setPasswordPreview] = useState<string | null>(null)
|
||||
const [createDialogOpen, setCreateDialogOpen] = useState(false)
|
||||
const autoOpenHandledRef = useRef(false)
|
||||
const [isCreatingAccount, setIsCreatingAccount] = useState(false)
|
||||
const [createForm, setCreateForm] = useState<CreateAccountFormState>(() => createDefaultAccountForm())
|
||||
|
||||
|
|
@ -400,6 +409,13 @@ function AccountsTable({
|
|||
setCreateForm(createDefaultAccountForm())
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!autoOpenCreate || autoOpenHandledRef.current) return
|
||||
autoOpenHandledRef.current = true
|
||||
setCreateForm(createDefaultAccountForm())
|
||||
setCreateDialogOpen(true)
|
||||
}, [autoOpenCreate])
|
||||
|
||||
useEffect(() => {
|
||||
if (editAccount) {
|
||||
setEditForm({
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function GlobalQuickActions() {
|
|||
label: "Adicionar empresa",
|
||||
description: "Cadastrar novo cliente",
|
||||
icon: Building,
|
||||
href: "/admin/companies",
|
||||
href: "/admin/companies?quick=new-company",
|
||||
visible: Boolean(isAdmin),
|
||||
},
|
||||
{
|
||||
|
|
@ -47,7 +47,7 @@ export function GlobalQuickActions() {
|
|||
label: "Novo usuário",
|
||||
description: "Gestores / colaboradores",
|
||||
icon: UserPlus,
|
||||
href: "/admin/users",
|
||||
href: "/admin/users?quick=new-user",
|
||||
visible: Boolean(isAdmin),
|
||||
},
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue