From 82dc878502d2e59733b5618cbe4429cca6e0346c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Rafael=20Siqueira?= Date: Tue, 27 Jan 2026 18:34:13 -0300 Subject: [PATCH] add certs page --- api.saladeaula.digital/app/app.py | 1 + .../app/routes/orgs/__init__.py | 2 + .../app/routes/orgs/enrollments/certs.py | 29 ++++ .../app/routes/orgs/enrollments/scheduled.py | 3 +- .../app/components/app-sidebar.tsx | 11 +- .../routes/_.$orgid.billing._index/route.tsx | 124 +++++++++--------- .../routes/_.$orgid.certs._index/route.tsx | 91 ++++++++++++- .../routes/_.$orgid.enrollments.buy/route.tsx | 5 +- 8 files changed, 192 insertions(+), 74 deletions(-) create mode 100644 api.saladeaula.digital/app/routes/orgs/enrollments/certs.py diff --git a/api.saladeaula.digital/app/app.py b/api.saladeaula.digital/app/app.py index 3853c67..1b6cb33 100644 --- a/api.saladeaula.digital/app/app.py +++ b/api.saladeaula.digital/app/app.py @@ -54,6 +54,7 @@ app.include_router(orgs.add, prefix='/orgs') app.include_router(orgs.address, prefix='/orgs') app.include_router(orgs.admins, prefix='/orgs') app.include_router(orgs.billing, prefix='/orgs') +app.include_router(orgs.certs, prefix='/orgs') app.include_router(orgs.custom_pricing, prefix='/orgs') app.include_router(orgs.scheduled, prefix='/orgs') app.include_router(orgs.submissions, prefix='/orgs') diff --git a/api.saladeaula.digital/app/routes/orgs/__init__.py b/api.saladeaula.digital/app/routes/orgs/__init__.py index f351e67..5b422ee 100644 --- a/api.saladeaula.digital/app/routes/orgs/__init__.py +++ b/api.saladeaula.digital/app/routes/orgs/__init__.py @@ -10,6 +10,7 @@ from .address import router as address from .admins import router as admins from .billing import router as billing from .custom_pricing import router as custom_pricing +from .enrollments.certs import router as certs from .enrollments.scheduled import router as scheduled from .enrollments.submissions import router as submissions from .seats import router as seats @@ -23,6 +24,7 @@ __all__ = [ 'admins', 'billing', 'custom_pricing', + 'certs', 'scheduled', 'submissions', 'seats', diff --git a/api.saladeaula.digital/app/routes/orgs/enrollments/certs.py b/api.saladeaula.digital/app/routes/orgs/enrollments/certs.py new file mode 100644 index 0000000..4b99a8c --- /dev/null +++ b/api.saladeaula.digital/app/routes/orgs/enrollments/certs.py @@ -0,0 +1,29 @@ +from datetime import date +from typing import Annotated + +from aws_lambda_powertools import Logger +from aws_lambda_powertools.event_handler.api_gateway import Router +from aws_lambda_powertools.event_handler.openapi.params import Query +from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair + +from boto3clients import dynamodb_client +from config import ENROLLMENT_TABLE + +logger = Logger(__name__) +router = Router() +dyn = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) + + +@router.get('//enrollments/certs') +def certs( + org_id: str, + month: Annotated[date, Query()], +): + year_month = month.strftime('%Y-%m') + + return dyn.collection.query( + KeyPair( + f'CERT_REPORTING#ORG#{org_id}', + f'MONTH#{year_month}#ENROLLMENT', + ), + ) diff --git a/api.saladeaula.digital/app/routes/orgs/enrollments/scheduled.py b/api.saladeaula.digital/app/routes/orgs/enrollments/scheduled.py index be0fd0e..82f0425 100644 --- a/api.saladeaula.digital/app/routes/orgs/enrollments/scheduled.py +++ b/api.saladeaula.digital/app/routes/orgs/enrollments/scheduled.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Annotated, cast +from typing import Annotated from aws_lambda_powertools import Logger from aws_lambda_powertools.event_handler.api_gateway import Router @@ -11,7 +11,6 @@ from pydantic import FutureDatetime from api_gateway import JSONResponse from boto3clients import dynamodb_client from config import ENROLLMENT_TABLE -from routes.orgs import billing from ...enrollments.enroll import Context, Enrollment, Org, Subscription, enroll_now diff --git a/apps/admin.saladeaula.digital/app/components/app-sidebar.tsx b/apps/admin.saladeaula.digital/app/components/app-sidebar.tsx index a693853..e1b2d88 100644 --- a/apps/admin.saladeaula.digital/app/components/app-sidebar.tsx +++ b/apps/admin.saladeaula.digital/app/components/app-sidebar.tsx @@ -3,6 +3,7 @@ import { BookCopyIcon, CalendarClockIcon, + FileBadgeIcon, // FileBadgeIcon, GraduationCap, LayoutDashboardIcon, @@ -65,11 +66,11 @@ const data = { url: '/enrollments', icon: GraduationCap }, - // { - // title: 'Certificações', - // url: '/certs', - // icon: FileBadgeIcon - // }, + { + title: 'Certificações', + url: '/certs', + icon: FileBadgeIcon + }, { title: 'Agendamentos', url: '/scheduled', diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx index 33779b4..4ce1619 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx @@ -76,73 +76,71 @@ export default function Route({ const search = searchParams.get('s') as string return ( - <> - }> -
-

- Resumo de cobranças -

-

- Acompanhe as cobranças em tempo real e garanta mais eficiência no - controle financeiro. -

-
+ }> +
+

+ Resumo de cobranças +

+

+ Acompanhe as cobranças em tempo real e garanta mais eficiência no + controle financeiro. +

+
- - {({ items = [], ...billing }) => { - const { - icon: Icon, - label: status, - color - } = statuses?.[billing?.status || 'CLOSED'] + + {({ items = [], ...billing }) => { + const { + icon: Icon, + label: status, + color + } = statuses?.[billing?.status || 'CLOSED'] - return ( - - -
-
- - Digite /{' '} - para pesquisar - - } - onChange={(value) => - setSearchParams((searchParams) => { - searchParams.set('s', String(value)) - return searchParams - }) - } - /> -
- - + +
+
+ + Digite / para + pesquisar + + } + onChange={(value) => + setSearchParams((searchParams) => { + searchParams.set('s', String(value)) + return searchParams + }) + } /> - -
- - - - ) - }} - - - + + + +
+ + +
+ + ) + }} + + ) } @@ -217,7 +215,7 @@ function List({ items, search }) { {charges.length ? ( <> - + Colaborador Curso Matriculado por diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.certs._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.certs._index/route.tsx index bd2569f..32c57a3 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.certs._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.certs._index/route.tsx @@ -1,12 +1,46 @@ import type { Route } from './+types/route' +import { Suspense } from 'react' +import { Await } from 'react-router' + +import { DateTime } from '@repo/ui/components/datetime' +import { Skeleton } from '@repo/ui/components/skeleton' +import { Card, CardContent } from '@repo/ui/components/ui/card' +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow +} from '@repo/ui/components/ui/table' +import { request as req } from '@repo/util/request' + export function meta({}) { return [{ title: 'Certificações' }] } -export default function Route({}: Route.ComponentProps) { +export async function loader({ context, request, params }: Route.LoaderArgs) { + const { searchParams } = new URL(request.url) + + const month = + searchParams.get('month') || new Date().toISOString().slice(0, 10) + const reporting = req({ + url: `/orgs/${params.orgid}/enrollments/certs?month=${month}`, + context, + request + }).then((r) => r.json()) + + return { + reporting + } +} + +export default function Route({ + loaderData: { reporting } +}: Route.ComponentProps) { return ( - <> + }>

Gerenciar certificações @@ -16,6 +50,57 @@ export default function Route({}: Route.ComponentProps) { prazos e renovações com facilidade.

- + + + + + + + Colaborador + Curso + Matriculado em + Concluído em + Cert. válido até + + + + + {({ items = [] }) => { + return ( + <> + {items.map( + ({ + course, + user, + enrolled_at, + completed_at, + expires_at + }) => { + return ( + + {user.name} + {course.name} + + {enrolled_at} + + + {completed_at} + + + {expires_at} + + + ) + } + )} + + ) + }} + + +
+
+
+
) } diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/route.tsx index a7addee..4a93b0f 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/route.tsx @@ -190,7 +190,10 @@ export default function Route({