diff --git a/angular.json b/angular.json index 05bbb10a..1857f646 100644 --- a/angular.json +++ b/angular.json @@ -2,7 +2,8 @@ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "cli": { - "packageManager": "npm" + "packageManager": "npm", + "analytics": false }, "newProjectRoot": "projects", "projects": { @@ -38,8 +39,8 @@ }, { "type": "anyComponentStyle", - "maximumWarning": "4kB", - "maximumError": "8kB" + "maximumWarning": "10kB", + "maximumError": "12kB" } ], "outputHashing": "all" diff --git a/formaçãometacase.ts b/formaçãometacase.ts new file mode 100644 index 00000000..9640692e --- /dev/null +++ b/formaçãometacase.ts @@ -0,0 +1,311 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +interface Course { + category: string; + title: string; + description: string; + level: string; + duration: string; + badge: string; + image: string; +} + +@Component({ + selector: 'app-courses-page', + standalone: true, + imports: [CommonModule], + template: ` +
+
+ Learning Hub +

As nossas Componentes

+

+ Conehcimento das componentes de TargetOne, atraves de um conjunto de formações interativas e práticas, projetadas para potencializar o dominio das nossas soluções. +

+
+
+ +
+
+
+

Formações Dispiniveis

+

Formações diponiveis de TargetOne disponiveis para fazer

+
+ +
+ {{ courses.length }} courses +
+
+ +
+
+
+ {{ course.badge }} +
+ +
+ {{ course.category }} +

{{ course.title }}

+

{{ course.description }}

+ +
+ {{ course.level }} + {{ course.duration }} +
+ + +
+
+
+
+ `, + styles: [` + :host { + display: block; + min-height: 100vh; + background: + radial-gradient(circle at top left, rgba(94, 96, 206, 0.20), transparent 28%), + radial-gradient(circle at top right, rgba(76, 201, 240, 0.18), transparent 30%), + linear-gradient(180deg, #0b1020 0%, #11182d 35%, #f5f7fb 35%, #f5f7fb 100%); + color: #101828; + font-family: Inter, Arial, sans-serif; + } + + * { + box-sizing: border-box; + } + + .hero { + padding: 72px 24px 56px; + color: #ffffff; + } + + .hero__content { + max-width: 1200px; + margin: 0 auto; + } + + .eyebrow { + display: inline-flex; + padding: 8px 14px; + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + font-size: 12px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + margin-bottom: 18px; + } + + .hero h1 { + margin: 0 0 16px; + font-size: clamp(2.2rem, 5vw, 4rem); + line-height: 1.05; + font-weight: 800; + } + + .hero p { + max-width: 700px; + margin: 0; + color: rgba(255, 255, 255, 0.82); + font-size: 1.05rem; + line-height: 1.7; + } + + .courses-page { + max-width: 1200px; + margin: 0 auto; + padding: 0 24px 72px; + } + + .courses-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + margin-bottom: 28px; + } + + .courses-header h2 { + margin: 0 0 8px; + font-size: 2rem; + color: #111827; + } + + .courses-header p { + margin: 0; + color: #667085; + } + + .courses-summary { + background: #ffffff; + border: 1px solid #e4e7ec; + border-radius: 16px; + padding: 14px 18px; + box-shadow: 0 10px 30px rgba(16, 24, 40, 0.06); + font-weight: 700; + white-space: nowrap; + } + + .courses-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 24px; + } + + .course-card { + overflow: hidden; + border-radius: 24px; + background: #ffffff; + border: 1px solid #eaecf0; + box-shadow: 0 20px 45px rgba(16, 24, 40, 0.08); + transition: transform 0.25s ease, box-shadow 0.25s ease; + } + + .course-card:hover { + transform: translateY(-6px); + box-shadow: 0 24px 55px rgba(16, 24, 40, 0.12); + } + + .course-card__image { + position: relative; + min-height: 220px; + background-size: cover; + background-position: center; + } + + .course-card__image::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(180deg, rgba(17, 24, 39, 0.10) 0%, rgba(17, 24, 39, 0.45) 100%); + } + + .badge { + position: absolute; + top: 18px; + left: 18px; + z-index: 1; + display: inline-flex; + padding: 8px 12px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.92); + color: #111827; + font-size: 12px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.04em; + } + + .course-card__content { + padding: 24px; + } + + .category { + display: inline-block; + margin-bottom: 12px; + color: #4f46e5; + font-weight: 700; + font-size: 0.88rem; + } + + .course-card h3 { + margin: 0 0 12px; + font-size: 1.35rem; + line-height: 1.3; + color: #101828; + } + + .course-card p { + margin: 0 0 18px; + color: #667085; + line-height: 1.65; + } + + .meta { + display: flex; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 20px; + } + + .meta span { + padding: 8px 12px; + border-radius: 999px; + background: #f2f4f7; + color: #344054; + font-size: 0.88rem; + font-weight: 600; + } + + button { + width: 100%; + border: 0; + border-radius: 14px; + padding: 14px 16px; + background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); + color: #ffffff; + font-size: 0.98rem; + font-weight: 700; + cursor: pointer; + } + + button:hover { + filter: brightness(1.05); + } + + @media (max-width: 1024px) { + .courses-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + + @media (max-width: 768px) { + .hero { + padding-top: 56px; + } + + .courses-header { + flex-direction: column; + align-items: flex-start; + } + + .courses-grid { + grid-template-columns: 1fr; + } + } + `] +}) +export class CoursesPageComponent { + courses: Course[] = [ + { + category: 'Automation Basics', + title: 'Introduction to Intelligent Automation', + description: 'Aprenda os fundamentos da automação, os principais conceitos e como identificar oportunidades de melhoria em processos.', + level: 'Beginner', + duration: '2h 30min', + badge: 'Popular', + image: 'https://images.unsplash.com/photo-1516321318423-f06f85e504b3?auto=format&fit=crop&w=1200&q=80' + }, + { + category: 'Development', + title: 'Build Your First Automation Project', + description: 'Curso prático com abordagem hands-on para criar, testar e publicar o seu primeiro fluxo de automação passo a passo.', + level: 'Intermediate', + duration: '4h 10min', + badge: 'Hands-on', + image: 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?auto=format&fit=crop&w=1200&q=80' + }, + { + category: 'AI + Processes', + title: 'AI Tools for Modern Operations', + description: 'Descubra como combinar automação e ferramentas de IA para acelerar tarefas repetitivas e melhorar a eficiência operacional.', + level: 'Advanced', + duration: '3h 45min', + badge: 'New', + image: 'https://images.unsplash.com/photo-1677442136019-21780ecad995?auto=format&fit=crop&w=1200&q=80' + } + ]; +} diff --git a/images/categorias/contabilizacoes.svg b/images/categorias/contabilizacoes.svg new file mode 100644 index 00000000..7eac2dcd --- /dev/null +++ b/images/categorias/contabilizacoes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/categorias/extratos.svg b/images/categorias/extratos.svg new file mode 100644 index 00000000..1465961c --- /dev/null +++ b/images/categorias/extratos.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/categorias/operacoes-financeiras.svg b/images/categorias/operacoes-financeiras.svg new file mode 100644 index 00000000..d33f280e --- /dev/null +++ b/images/categorias/operacoes-financeiras.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/categorias/parametros.svg b/images/categorias/parametros.svg new file mode 100644 index 00000000..db0912bb --- /dev/null +++ b/images/categorias/parametros.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/categorias/reconciliacoes-bancarias.svg b/images/categorias/reconciliacoes-bancarias.svg new file mode 100644 index 00000000..73afcc43 --- /dev/null +++ b/images/categorias/reconciliacoes-bancarias.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/categorias/tesouraria.svg b/images/categorias/tesouraria.svg new file mode 100644 index 00000000..62e06bb5 --- /dev/null +++ b/images/categorias/tesouraria.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/Powerpoints/Configurar o Servidor.txt b/public/Powerpoints/Configurar o Servidor.txt new file mode 100644 index 00000000..01ce588d --- /dev/null +++ b/public/Powerpoints/Configurar o Servidor.txt @@ -0,0 +1,114 @@ +######## Como publicar angular work ############ + + +npm install -> se necessário +ng serve -> se necessário + +ng build -> gerar o dist + +ssh teu_user@IP_DO_SERVIDOR -> comando para entrar no serviro (meter user@ip) + +##Criar pasta do site no servidor eu usei um docker## + +mkdir -p /docker/angular/metacaseform + +### Copiar os ficheiros do PC para o servidor onde coloquei a pagina da metacase do Docker ### + +scp -r dist/form_metacase/browser/* USERNAME@IP:/docker/angular/metacaseform/ + +#### criar o composse.yml e as configurações para o Nginx para criar o Docker #### + +nano /docker/angular/metacaseform/nginx.conf + +nano /docker/angular/metacaseform/docker-compose.yml + +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location = /favicon.ico { + log_not_found off; + access_log off; + try_files $uri =204; + } +} + +version: "3.9" + +services: + angular-metacase: + image: nginx:latest + container_name: angular-metacase + restart: unless-stopped + ports: + - "8090:80" + volumes: + - /docker/angular/metacaseform/app:/usr/share/nginx/html:ro + - /docker/angular/metacaseform/nginx.conf:/etc/nginx/conf.d/default.conf:ro + + +##### arrancar o container ##### + + +cd /docker/angular/metacaseform +docker compose up -d + + +#### IR ao Ngnix configurar o acesso http…. blabla e escolher uma porta livre no caso especifico escolhi a 8090 #### + +Block Common Exploits ✓ +Websockets Support ✓ + + +Request a new certificate +Force SSL ✓ +HTTP/2 Support ✓ + + + +##### Fui ao meu provaider de domínio registar o metacasehub #### + + + +https://www.ovh.com/manager + + + +2️⃣ Ir para a gestão do domínio + +No menu da esquerda, Web Cloud → Domains + +Selecionar o domínio: + +Clica em DNS Zone + +Criar ou editar o registo + +Clica em Add an entry Escolher A CNAE: + +Subdomain: metacasehub (NESTE cASO) +Target: IP_PUBLICO +TTL: Default + +Exemplo: + +metacasehub → 85.xxx.xxx.xxx + + +Saber o IP publico no meu caso eu não usei isto porque estou a usar o duck DNS mas pode ser feito por aqui: + +👉 https://whatismyipaddress.com/ + +ou correr no terminal: + +curl ifconfig.me + + +e deve estar \ No newline at end of file diff --git a/public/Powerpoints/Manual Metacase.doc b/public/Powerpoints/Manual Metacase.doc new file mode 100644 index 00000000..26e4800d Binary files /dev/null and b/public/Powerpoints/Manual Metacase.doc differ diff --git a/public/Powerpoints/Manual Metacase.docx b/public/Powerpoints/Manual Metacase.docx new file mode 100644 index 00000000..a02f629d Binary files /dev/null and b/public/Powerpoints/Manual Metacase.docx differ diff --git a/public/Powerpoints/Manual Metacase.pdf b/public/Powerpoints/Manual Metacase.pdf new file mode 100644 index 00000000..33751fb4 Binary files /dev/null and b/public/Powerpoints/Manual Metacase.pdf differ diff --git a/public/Powerpoints/TargetOne.pptx b/public/Powerpoints/TargetOne.pptx new file mode 100644 index 00000000..0962bb50 Binary files /dev/null and b/public/Powerpoints/TargetOne.pptx differ diff --git a/public/Powerpoints/TargetOne/Diapositivo1.PNG b/public/Powerpoints/TargetOne/Diapositivo1.PNG new file mode 100644 index 00000000..7d90f134 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo1.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo10.PNG b/public/Powerpoints/TargetOne/Diapositivo10.PNG new file mode 100644 index 00000000..245b6496 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo10.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo11.PNG b/public/Powerpoints/TargetOne/Diapositivo11.PNG new file mode 100644 index 00000000..7a0aadcd Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo11.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo12.PNG b/public/Powerpoints/TargetOne/Diapositivo12.PNG new file mode 100644 index 00000000..32033539 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo12.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo13.PNG b/public/Powerpoints/TargetOne/Diapositivo13.PNG new file mode 100644 index 00000000..42d3b037 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo13.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo14.PNG b/public/Powerpoints/TargetOne/Diapositivo14.PNG new file mode 100644 index 00000000..de01fdef Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo14.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo2.PNG b/public/Powerpoints/TargetOne/Diapositivo2.PNG new file mode 100644 index 00000000..5d37c909 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo2.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo3.PNG b/public/Powerpoints/TargetOne/Diapositivo3.PNG new file mode 100644 index 00000000..acfc9b84 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo3.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo4.PNG b/public/Powerpoints/TargetOne/Diapositivo4.PNG new file mode 100644 index 00000000..52271e87 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo4.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo5.PNG b/public/Powerpoints/TargetOne/Diapositivo5.PNG new file mode 100644 index 00000000..0470fe9b Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo5.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo6.PNG b/public/Powerpoints/TargetOne/Diapositivo6.PNG new file mode 100644 index 00000000..76783ac9 Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo6.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo7.PNG b/public/Powerpoints/TargetOne/Diapositivo7.PNG new file mode 100644 index 00000000..c4350e7f Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo7.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo8.PNG b/public/Powerpoints/TargetOne/Diapositivo8.PNG new file mode 100644 index 00000000..75cb5d5b Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo8.PNG differ diff --git a/public/Powerpoints/TargetOne/Diapositivo9.PNG b/public/Powerpoints/TargetOne/Diapositivo9.PNG new file mode 100644 index 00000000..5381b84a Binary files /dev/null and b/public/Powerpoints/TargetOne/Diapositivo9.PNG differ diff --git a/public/Powerpoints/~$TargetOne.pptx b/public/Powerpoints/~$TargetOne.pptx new file mode 100644 index 00000000..5e18c209 Binary files /dev/null and b/public/Powerpoints/~$TargetOne.pptx differ diff --git a/public/categorias/contabilizacoes.svg b/public/categorias/contabilizacoes.svg new file mode 100644 index 00000000..7eac2dcd --- /dev/null +++ b/public/categorias/contabilizacoes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/categorias/extratos.svg b/public/categorias/extratos.svg new file mode 100644 index 00000000..1465961c --- /dev/null +++ b/public/categorias/extratos.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/categorias/operacoes-financeiras.svg b/public/categorias/operacoes-financeiras.svg new file mode 100644 index 00000000..d33f280e --- /dev/null +++ b/public/categorias/operacoes-financeiras.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/categorias/reconciliacoes-bancarias.svg b/public/categorias/reconciliacoes-bancarias.svg new file mode 100644 index 00000000..73afcc43 --- /dev/null +++ b/public/categorias/reconciliacoes-bancarias.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/categorias/tesouraria.svg b/public/categorias/tesouraria.svg new file mode 100644 index 00000000..62e06bb5 --- /dev/null +++ b/public/categorias/tesouraria.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/imagenscursos/Extratos.jpg b/public/imagenscursos/Extratos.jpg new file mode 100644 index 00000000..f3fbb1a8 Binary files /dev/null and b/public/imagenscursos/Extratos.jpg differ diff --git a/public/imagenscursos/Extratos.png b/public/imagenscursos/Extratos.png new file mode 100644 index 00000000..2df52b18 Binary files /dev/null and b/public/imagenscursos/Extratos.png differ diff --git a/public/imagenscursos/MetacaseSIbs.png b/public/imagenscursos/MetacaseSIbs.png new file mode 100644 index 00000000..28afa7f7 Binary files /dev/null and b/public/imagenscursos/MetacaseSIbs.png differ diff --git a/public/imagenscursos/Parametros.png b/public/imagenscursos/Parametros.png new file mode 100644 index 00000000..2b4af8fe Binary files /dev/null and b/public/imagenscursos/Parametros.png differ diff --git a/public/imagenscursos/Seguranças.png b/public/imagenscursos/Seguranças.png new file mode 100644 index 00000000..826a4dfb Binary files /dev/null and b/public/imagenscursos/Seguranças.png differ diff --git a/public/imagenscursos/learninghub.png b/public/imagenscursos/learninghub.png new file mode 100644 index 00000000..c97e794c Binary files /dev/null and b/public/imagenscursos/learninghub.png differ diff --git a/public/imagenscursos/reconciliacoes.png b/public/imagenscursos/reconciliacoes.png new file mode 100644 index 00000000..3b670fb4 Binary files /dev/null and b/public/imagenscursos/reconciliacoes.png differ diff --git a/public/imagenscursos/targetone.png b/public/imagenscursos/targetone.png new file mode 100644 index 00000000..c568261a Binary files /dev/null and b/public/imagenscursos/targetone.png differ diff --git a/public/logo-metacase-cor.svg b/public/logo-metacase-cor.svg new file mode 100644 index 00000000..bd2a3b22 --- /dev/null +++ b/public/logo-metacase-cor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/screenshots/Curso.jpg b/public/screenshots/Curso.jpg new file mode 100644 index 00000000..998b1a32 Binary files /dev/null and b/public/screenshots/Curso.jpg differ diff --git a/public/screenshots/Curso1.2.jpg b/public/screenshots/Curso1.2.jpg new file mode 100644 index 00000000..a7edbeb7 Binary files /dev/null and b/public/screenshots/Curso1.2.jpg differ diff --git a/public/screenshots/Curso1.3.jpg b/public/screenshots/Curso1.3.jpg new file mode 100644 index 00000000..9d8aa25b Binary files /dev/null and b/public/screenshots/Curso1.3.jpg differ diff --git a/public/screenshots/Curso1.4.jpg b/public/screenshots/Curso1.4.jpg new file mode 100644 index 00000000..45e26a16 Binary files /dev/null and b/public/screenshots/Curso1.4.jpg differ diff --git a/public/screenshots/Curso2.jpg b/public/screenshots/Curso2.jpg new file mode 100644 index 00000000..f80623a6 Binary files /dev/null and b/public/screenshots/Curso2.jpg differ diff --git a/public/screenshots/Descricaopgprincipal.jpg b/public/screenshots/Descricaopgprincipal.jpg new file mode 100644 index 00000000..2d0fcaea Binary files /dev/null and b/public/screenshots/Descricaopgprincipal.jpg differ diff --git a/public/screenshots/Pagina Principal.jpg b/public/screenshots/Pagina Principal.jpg new file mode 100644 index 00000000..0c27df33 Binary files /dev/null and b/public/screenshots/Pagina Principal.jpg differ diff --git a/public/screenshots/alterações.pptx b/public/screenshots/alterações.pptx new file mode 100644 index 00000000..22a4b7c5 Binary files /dev/null and b/public/screenshots/alterações.pptx differ diff --git a/public/screenshots/detalhecurso.jpg b/public/screenshots/detalhecurso.jpg new file mode 100644 index 00000000..395b77f5 Binary files /dev/null and b/public/screenshots/detalhecurso.jpg differ diff --git a/public/screenshots/detalhecurso2.jpg b/public/screenshots/detalhecurso2.jpg new file mode 100644 index 00000000..c9408c0e Binary files /dev/null and b/public/screenshots/detalhecurso2.jpg differ diff --git a/public/screenshots/menutextratos.png b/public/screenshots/menutextratos.png new file mode 100644 index 00000000..5441b450 Binary files /dev/null and b/public/screenshots/menutextratos.png differ diff --git a/public/screenshots/~$alterações.pptx b/public/screenshots/~$alterações.pptx new file mode 100644 index 00000000..5e18c209 Binary files /dev/null and b/public/screenshots/~$alterações.pptx differ diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index dc39edb5..6490b335 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,3 +1,23 @@ import { Routes } from '@angular/router'; +import { Formacaometacase } from './formacaometacase/formacaometacase'; +import { CourseDetailPageComponent } from './course-detail-page/course-detail-page'; +import { CourseLearningPageComponent } from './course-learning-page/course-learning-page'; -export const routes: Routes = []; +export const routes: Routes = [ + { + path: '', + component: Formacaometacase + }, + { + path: 'cursos/:slug', + component: CourseDetailPageComponent + }, + { + path: 'cursos/:slug/percurso', + component: CourseLearningPageComponent + }, + { + path: '**', + redirectTo: '' + } +]; diff --git a/src/app/app.spec.ts b/src/app/app.spec.ts index 27e7ed0b..8c88328b 100644 --- a/src/app/app.spec.ts +++ b/src/app/app.spec.ts @@ -1,10 +1,13 @@ import { TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; import { App } from './app'; +import { routes } from './app.routes'; describe('App', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [App], + providers: [provideRouter(routes)] }).compileComponents(); }); @@ -13,11 +16,4 @@ describe('App', () => { const app = fixture.componentInstance; expect(app).toBeTruthy(); }); - - it('should render title', async () => { - const fixture = TestBed.createComponent(App); - await fixture.whenStable(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, form_metacase'); - }); }); diff --git a/src/app/app.ts b/src/app/app.ts index 4f3f86dd..0abf33e4 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,12 +1,11 @@ -import { Component, signal } from '@angular/core'; +import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; @Component({ selector: 'app-root', + standalone: true, imports: [RouterOutlet], - templateUrl: './app.html', - styleUrl: './app.css' + template: `` }) export class App { - protected readonly title = signal('form_metacase'); } diff --git a/src/app/course-detail-page/course-detail-page.css b/src/app/course-detail-page/course-detail-page.css new file mode 100644 index 00000000..610b067b --- /dev/null +++ b/src/app/course-detail-page/course-detail-page.css @@ -0,0 +1,527 @@ +:host { + display: block; + min-height: 100vh; + background: #f8fafc; + color: #0f172a; +} + +* { + box-sizing: border-box; +} + +.course-detail-page { + min-height: 100vh; +} + +.course-intro { + background: + radial-gradient(circle at top left, rgba(37, 99, 235, 0.12), transparent 24%), + linear-gradient(180deg, #ffffff 0%, #f6f9fd 100%); + border-bottom: 1px solid #e2e8f0; +} + +.course-intro__inner { + display: grid; + grid-template-columns: minmax(0, 1.55fr) minmax(320px, 420px); + gap: 34px; + max-width: 1240px; + margin: 0 auto; + padding: 56px 24px 40px; +} + +.course-intro__main { + padding-top: 12px; +} + +.back-link { + display: inline-flex; + align-items: center; + margin-bottom: 20px; + color: #2563eb; + text-decoration: none; + font-weight: 700; +} + +.back-link:hover { + color: #1d4ed8; +} + +.intro-pills { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 18px; +} + +.intro-pill { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 34px; + padding: 0 14px; + border-radius: 999px; + background: #dbeafe; + color: #1d4ed8; + font-size: 0.86rem; + font-weight: 800; +} + +.intro-pill--muted { + background: #eff6ff; + color: #334155; +} + +.course-intro h1 { + max-width: 760px; + margin: 0 0 16px; + font-size: clamp(2.4rem, 5vw, 4rem); + line-height: 1.04; + letter-spacing: -0.03em; +} + +.lesson-image { + display: block; + margin: 30px auto; + max-width: 600px; + width: 100%; +} + +.intro-summary { + max-width: 760px; + margin: 0 0 24px; + color: #475569; + font-size: 1.06rem; + line-height: 1.75; + text-align: justify; +} + +.intro-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 14px; + max-width: 720px; + margin-bottom: 20px; +} + +.intro-stat { + padding: 18px 18px 16px; + border: 1px solid #dbe4f0; + border-radius: 22px; + background: #ffffff; +} + +.intro-stat span { + display: block; + margin-bottom: 8px; + color: #64748b; + font-size: 0.8rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; +} + +.intro-stat strong { + font-size: 1rem; +} + +.intro-icons { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.intro-icons__item { + width: auto; + height: 28px; +} + +.enroll-card { + overflow: hidden; + border: 1px solid #dbe4f0; + border-radius: 28px; + background: #ffffff; + box-shadow: 0 18px 42px rgba(15, 23, 42, 0.08); +} + +.enroll-card__media { + aspect-ratio: 16 / 10; + overflow: hidden; + background: #0f172a; +} + +.enroll-card__media img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.enroll-card__body { + padding: 22px; +} + +.enroll-card__topline { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 14px; +} + +.enroll-card__topline span { + display: inline-flex; + padding: 7px 11px; + border-radius: 999px; + background: #eff6ff; + color: #1d4ed8; + font-size: 0.8rem; + font-weight: 800; +} + +.enroll-card h2 { + margin: 0 0 10px; + font-size: 1.55rem; +} + +.enroll-card p { + margin: 0 0 18px; + color: #64748b; + line-height: 1.65; +} + +.detail-tabs { + position: sticky; + top: 0; + z-index: 20; + display: flex; + gap: 28px; + max-width: 1240px; + margin: 0 auto; + padding: 0 24px; + background: rgba(248, 250, 252, 0.94); + backdrop-filter: blur(12px); + border-bottom: 1px solid #e2e8f0; +} + +.detail-tabs a { + display: inline-flex; + align-items: center; + min-height: 62px; + color: #334155; + text-decoration: none; + font-weight: 800; + border-bottom: 3px solid transparent; +} + +.detail-tabs a:hover { + color: #0f172a; + border-bottom-color: #2563eb; +} + +.detail-layout { + display: grid; + grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.7fr); + gap: 30px; + max-width: 1240px; + margin: 0 auto; + padding: 28px 24px 72px; +} + +.detail-main { + display: flex; + flex-direction: column; + gap: 22px; +} + +.detail-panel, +.sidebar-card, +.course-not-found__card { + border: 1px solid #dbe4f0; + border-radius: 28px; + background: #ffffff; + box-shadow: 0 14px 34px rgba(15, 23, 42, 0.05); +} + +.detail-panel { + padding: 28px; +} + +.panel-header { + margin-bottom: 18px; +} + +.panel-header--split { + display: flex; + align-items: end; + justify-content: space-between; + gap: 16px; +} + +.panel-header__eyebrow, +.sidebar-card__eyebrow { + display: inline-flex; + margin-bottom: 10px; + color: #2563eb; + font-size: 1.2rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.panel-header h2 { + margin: 0; + font-size: 1.7rem; + line-height: 1.2; +} + +.panel-count { + display: inline-flex; + padding: 8px 12px; + border-radius: 999px; + background: #eff6ff; + color: #1d4ed8; + font-size: 0.82rem; + font-weight: 800; + white-space: nowrap; +} + +.detail-lead { + margin: 0 0 18px; + color: #475569; + line-height: 1.75; +} + +.detail-facts { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 14px; + margin-bottom: 18px; +} + +.detail-facts article, +.detail-box { + padding: 18px; + border: 1px solid #e5edf6; + border-radius: 22px; + background: #fbfdff; +} + +.detail-facts span { + display: block; + margin-bottom: 8px; + color: #64748b; + font-size: 0.78rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; +} + +.detail-columns { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 16px; +} + +.detail-box h3, +.learning-card h3, +.module-card__content h3 { + margin: 0 0 10px; + font-size: 1.08rem; +} + +.bullet-list, +.sidebar-list { + margin: 0; + padding-left: 18px; + color: #475569; + line-height: 1.75; +} + +.bullet-list li + li, +.sidebar-list li + li { + margin-top: 8px; +} + +.learning-grid { + display: grid; + grid-template-columns: repeat(1, minmax(0, 1fr)); + gap: 16px; +} + +.learning-card { + padding: 20px; + border: 1px solid #e5edf6; + border-radius: 22px; + background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%); +} + +.learning-card p, +.module-card__content p { + margin: 0; + color: #64748b; + line-height: 1.65; +} + +.module-list { + display: flex; + flex-direction: column; + gap: 14px; +} + +.module-card { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + gap: 16px; + align-items: start; + padding: 20px; + border: 1px solid #e5edf6; + border-radius: 24px; + background: #ffffff; +} + +.module-card__index { + display: inline-flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: 14px; + background: #eff6ff; + color: #1d4ed8; + font-weight: 800; +} + +.module-card__duration { + display: inline-flex; + padding: 8px 11px; + border-radius: 999px; + background: #f1f5f9; + color: #334155; + font-size: 0.82rem; + font-weight: 800; + white-space: nowrap; +} + +.sidebar-card { + position: sticky; + top: 92px; + padding: 24px; +} + +.sidebar-list { + margin-bottom: 18px; +} + +.sidebar-tags { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.sidebar-tags span { + display: inline-flex; + padding: 8px 12px; + border-radius: 999px; + background: #eff6ff; + color: #1d4ed8; + font-size: 0.84rem; + font-weight: 700; +} + +.button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 50px; + border: 0; + border-radius: 18px; + background: #1d4ed8; + color: #ffffff; + text-decoration: none; + font-size: 0.96rem; + font-weight: 800; + cursor: pointer; +} + +.button + .button { + margin-top: 12px; +} + +.button--secondary { + background: #eff6ff; + color: #1d4ed8; +} + +.course-not-found { + min-height: 100vh; + display: grid; + place-items: center; + padding: 24px; +} + +.course-not-found__card { + max-width: 520px; + padding: 32px; + text-align: center; +} + +.course-not-found__card h1 { + margin: 0 0 12px; +} + +.course-not-found__card p { + margin: 0 0 20px; + color: #64748b; +} + +@media (max-width: 1024px) { + .course-intro__inner, + .detail-layout { + grid-template-columns: 1fr; + } + + .sidebar-card { + position: static; + } +} + +@media (max-width: 768px) { + .course-intro__inner { + padding: 40px 20px 28px; + } + + .detail-tabs { + gap: 18px; + overflow-x: auto; + padding: 0 20px; + } + + .detail-layout { + padding: 22px 20px 56px; + } + + .intro-stats, + .detail-facts, + .detail-columns, + .learning-grid { + grid-template-columns: 1fr; + } + + .detail-panel, + .sidebar-card, + .course-not-found__card { + border-radius: 22px; + } + + .detail-panel { + padding: 22px; + } + + .panel-header--split, + .module-card { + grid-template-columns: 1fr; + } + + .module-card__duration { + justify-self: start; + } +} diff --git a/src/app/course-detail-page/course-detail-page.html b/src/app/course-detail-page/course-detail-page.html new file mode 100644 index 00000000..0056551f --- /dev/null +++ b/src/app/course-detail-page/course-detail-page.html @@ -0,0 +1,121 @@ + +
+
+
+
+ Voltar ao menu das formações + +

{{ course.title }}

+

{{ course.summary }}

+ +
+
+ Informação geral da formação +

{{ course.description }}

+
+ +
+
+ Idioma + {{ course.language }} +
+
+ Formato + {{ course.format }} +
+
+ Duração + {{ course.duration }} +
+
+ Modú los + {{ course.modules.length }} +
+
+ Pré-requisitos +
    +
  • {{ item }}
  • +
+
+
+ Público-Alvo +
    +
  • {{ item }}
  • +
+
+
+
+
+ + +
+
+ +
+ +
+
+
+
+ Estrutura da formação + +
+ + {{ course.modules.length }} lições +
+ +
+
+
{{ index + 1 }}
+ +
+

{{ module.title }}

+

{{ module.description }}

+
+ + {{ module.duration }} +
+
+
+
+ + +
+
+
+ + +
+
+

Formação não encontrada

+

A formação selecionada não está disponível neste momento.

+ Voltar aos cursos +
+
+
diff --git a/src/app/course-detail-page/course-detail-page.ts b/src/app/course-detail-page/course-detail-page.ts new file mode 100644 index 00000000..cae8a1f9 --- /dev/null +++ b/src/app/course-detail-page/course-detail-page.ts @@ -0,0 +1,22 @@ +import { CommonModule } from '@angular/common'; +import { Component, computed, inject } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { ActivatedRoute, RouterLink } from '@angular/router'; +import { getCourseBySlug } from '../data/courses'; + +@Component({ + selector: 'app-course-detail-page', + standalone: true, + imports: [CommonModule, RouterLink], + templateUrl: './course-detail-page.html', + styleUrl: './course-detail-page.css' +}) +export class CourseDetailPageComponent { + private readonly route = inject(ActivatedRoute); + private readonly paramMap = toSignal(this.route.paramMap); + + readonly course = computed(() => { + const slug = this.paramMap()?.get('slug') ?? null; + return getCourseBySlug(slug); + }); +} diff --git a/src/app/course-learning-page/course-learning-page.css b/src/app/course-learning-page/course-learning-page.css new file mode 100644 index 00000000..8409716c --- /dev/null +++ b/src/app/course-learning-page/course-learning-page.css @@ -0,0 +1,740 @@ +:host { + display: block; + min-height: 100vh; + background: #f8fafc; + color: #0f172a; +} + +* { + box-sizing: border-box; +} + +.learning-page { + min-height: 100vh; +} + +.learning-header { + border-bottom: 1px solid #e2e8f0; + background: + radial-gradient(circle at top left, rgba(37, 99, 235, 0.12), transparent 28%), + linear-gradient(180deg, #ffffff 0%, #f8fbff 100%); +} + +.learning-header__inner { + display: flex; + align-items: end; + justify-content: space-between; + gap: 24px; + max-width: 1280px; + margin: 0 auto; + padding: 40px 24px 28px; +} + +.back-link { + display: inline-flex; + margin-bottom: 18px; + color: #2563eb; + text-decoration: none; + font-weight: 700; +} + +.course-kicker { + margin: 0 0 10px; + color: #2563eb; + font-size: 0.82rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.learning-header h1 { + margin: 0; + font-size: clamp(2.2rem, 4vw, 3.6rem); + line-height: 1.06; + letter-spacing: -0.03em; +} + +.progress-card { + min-width: 260px; + padding: 18px 20px; + border: 1px solid #dbe4f0; + border-radius: 24px; + background: #ffffff; + box-shadow: 0 16px 30px rgba(15, 23, 42, 0.05); +} + +.progress-card__label { + display: block; + margin-bottom: 8px; + color: #64748b; + font-size: 0.8rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.progress-card strong { + display: block; + margin-bottom: 14px; + font-size: 1rem; +} + +.progress-bar { + height: 8px; + border-radius: 999px; + background: #e2e8f0; + overflow: hidden; +} + +.progress-bar span { + display: block; + width: 24%; + height: 100%; + border-radius: inherit; + background: linear-gradient(90deg, #1d4ed8 0%, #3b82f6 100%); +} + +.learning-layout { + display: grid; + grid-template-columns: 320px minmax(0, 1fr); + gap: 28px; + max-width: 1280px; + margin: 0 auto; + padding: 28px 24px 64px; +} + +.learning-sidebar { + position: relative; +} + +.sidebar-panel, +.content-panel, +.course-not-found__card { + border: 1px solid #dbe4f0; + border-radius: 28px; + background: #ffffff; + box-shadow: 0 14px 34px rgba(15, 23, 42, 0.05); +} + +.sidebar-panel { + position: sticky; + top: 24px; + padding: 22px; +} + +.sidebar-panel__top { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 18px; +} + +.sidebar-panel__eyebrow { + color: #2563eb; + font-size: 0.78rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.module-nav { + display: flex; + flex-direction: column; + gap: 12px; +} + +.module-nav__item { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + padding: 0; + border: 1px solid #e5edf6; + border-radius: 20px; + background: #f8fafc; +} + +.module-nav__trigger { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + gap: 12px; + width: 100%; + padding: 14px; + border: 0; + border-radius: inherit; + background: transparent; + text-align: left; + cursor: pointer; +} + +.module-nav__item--active { + border-color: #bfdbfe; + background: #eff6ff; +} + +.module-nav__index { + display: inline-flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + border-radius: 12px; + background: #ffffff; + color: #1d4ed8; + font-weight: 800; +} + +.module-nav__content h3 { + margin: 0 0 6px; + font-size: 0.98rem; +} + +.module-nav__content p { + margin: 0; + color: #64748b; + font-size: 0.9rem; +} + +.learning-main { + display: flex; + flex-direction: column; + gap: 22px; +} + +.content-panel { + padding: 28px; +} + +.content-panel__header { + display: flex; + align-items: end; + justify-content: space-between; + gap: 18px; + margin-bottom: 18px; +} + +.content-panel__eyebrow { + display: inline-flex; + margin-bottom: 10px; + color: #2563eb; + font-size: 0.78rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.content-panel__header h2 { + margin: 0; + font-size: 1.8rem; + line-height: 1.15; +} + +.lesson-duration { + display: inline-flex; + padding: 8px 12px; + border-radius: 999px; + background: #eff6ff; + color: #1d4ed8; + font-size: 0.84rem; + font-weight: 800; + white-space: nowrap; +} + +.content-intro { + margin: 0 0 18px; + color: #475569; + line-height: 1.75; + white-space: pre-line; + text-align: justify +} + +.resource-download-card { + display: flex; + align-items: center; + gap: 16px; + margin: 0 0 22px; + padding: 18px 20px; + border: 1px solid #bfdbfe; + border-radius: 22px; + background: linear-gradient(135deg, #eff6ff 0%, #ffffff 100%); + color: inherit; + text-decoration: none; + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; +} + +.resource-download-card:hover { + transform: translateY(-1px); + border-color: #60a5fa; + box-shadow: 0 16px 32px rgba(37, 99, 235, 0.12); +} + +.resource-download-card__icon { + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 56px; + width: 56px; + height: 56px; + border-radius: 18px; + background: #dbeafe; + color: #1d4ed8; +} + +.resource-download-card__icon svg { + width: 28px; + height: 28px; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 1.8; +} + +.resource-download-card__content { + display: flex; + flex: 1; + flex-direction: column; + gap: 4px; + min-width: 0; +} + +.resource-download-card__eyebrow { + color: #2563eb; + font-size: 0.78rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.resource-download-card__content strong { + font-size: 1rem; +} + +.resource-download-card__content span:last-child { + color: #64748b; + line-height: 1.5; +} + +.resource-download-card__action { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 42px; + padding: 0 16px; + border-radius: 999px; + background: #1d4ed8; + color: #ffffff; + font-size: 0.88rem; + font-weight: 800; + white-space: nowrap; +} + +.course-topics { + margin: 0 0 18px; + color: #475569; + line-height: 1.75; + text-align: justify; + padding-left: 20px; +} + +.course-topics li { + margin-bottom: 6px; +} + +.course-topics li::before { + content: "✓"; + color: #475569; + margin: 0 0 18px; + +} + +.content-icons { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 22px; +} + +.content-icons__item { + width: auto; + height: 26px; +} + +.lesson-section + .lesson-section { + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid #e5edf6; +} + +.module-sequence { + display: flex; + flex-direction: column; + gap: 18px; +} + +.learning-module { + scroll-margin-top: 28px; + padding: 20px; + border: 1px solid #e5edf6; + border-radius: 24px; + background: #ffffff; +} + +.learning-module__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 10px; +} + +.module-description { + margin: 0 0 14px; + color: #475569; + line-height: 1.7; +} + +.lesson-section h3, +.question-card h3 { + margin: 0 0 10px; + font-size: 1.16rem; +} + +.lesson-section p, +.question-note { + margin: 0; + color: #64748b; + line-height: 1.75; + text-align: justify; + white-space: pre-line; +} + +.lesson-section p + p { + margin-top: 12px; +} + +.lesson-image { + display: block; + width: min(100%, 860px); + margin: 18px auto; + border-radius: 18px; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.12); + cursor: zoom-in; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.lesson-image:hover { + transform: scale(1.01); + box-shadow: 0 22px 48px rgba(15, 23, 42, 0.16); +} + +.presentation-viewer { + margin-top: 24px; + padding: 22px; + border: 1px solid #dbe4f0; + border-radius: 24px; + background: linear-gradient(180deg, #eff6ff 0%, #ffffff 100%); +} + +.presentation-viewer__header { + display: flex; + align-items: end; + justify-content: space-between; + gap: 16px; + margin-bottom: 16px; +} + +.presentation-viewer__header h3 { + margin: 0; + font-size: 1.12rem; +} + +.presentation-viewer__counter, +.image-lightbox__counter { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 40px; + padding: 0 14px; + border-radius: 999px; + background: #dbeafe; + color: #1d4ed8; + font-size: 0.82rem; + font-weight: 800; + white-space: nowrap; +} + +.presentation-viewer__stage { + overflow: hidden; + border-radius: 20px; + background: #0f172a; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); +} + +.presentation-viewer__slide { + display: block; + width: 100%; + aspect-ratio: 16 / 9; + object-fit: contain; + background: #0f172a; + cursor: zoom-in; +} + +.presentation-viewer__actions { + display: flex; + justify-content: flex-end; + gap: 12px; + margin-top: 16px; +} + +.presentation-viewer__button { + min-height: 44px; + padding: 0 18px; + border: 0; + border-radius: 14px; + background: #1d4ed8; + color: #ffffff; + font-size: 0.9rem; + font-weight: 800; + cursor: pointer; +} + +.presentation-viewer__button:disabled { + opacity: 0.55; + cursor: not-allowed; +} + +.image-lightbox { + position: fixed; + inset: 0; + z-index: 1000; + display: grid; + place-items: center; + padding: 24px; + background: rgba(15, 23, 42, 0.82); + backdrop-filter: blur(6px); +} + +.image-lightbox__dialog { + position: relative; + max-width: min(1200px, 100%); + max-height: 100%; +} + +.image-lightbox__toolbar { + position: absolute; + top: -12px; + right: -12px; + z-index: 1; + display: flex; + align-items: center; + gap: 8px; +} + +.image-lightbox__action, +.image-lightbox__close { + min-width: 48px; + min-height: 40px; + padding: 0 14px; + border: 0; + border-radius: 999px; + background: #ffffff; + color: #0f172a; + font-size: 0.86rem; + font-weight: 800; + cursor: pointer; + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.2); +} + +.image-lightbox__close { + min-width: 96px; +} + +.image-lightbox__viewport { + overflow: auto; + max-width: min(1200px, calc(100vw - 48px)); + max-height: calc(100vh - 48px); + border-radius: 20px; + cursor: zoom-in; +} + +.image-lightbox__image { + display: block; + max-width: min(1200px, calc(100vw - 48px)); + max-height: calc(100vh - 48px); + border-radius: 20px; + box-shadow: 0 28px 70px rgba(15, 23, 42, 0.35); + transition: transform 0.18s ease; + user-select: none; +} + +.question-list { + display: flex; + flex-direction: column; + gap: 16px; +} + +.question-card { + padding: 20px; + border: 1px solid #e5edf6; + border-radius: 24px; + background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%); +} + +.question-card__number { + display: inline-flex; + margin-bottom: 12px; + color: #2563eb; + font-size: 0.78rem; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.question-options { + display: grid; + gap: 10px; + margin: 16px 0 14px; +} + +.question-option { + min-height: 50px; + border: 1px solid #dbe4f0; + border-radius: 16px; + background: #ffffff; + color: #0f172a; + font-size: 0.95rem; + font-weight: 700; + text-align: left; + padding: 0 16px; + cursor: pointer; +} + +.question-option:hover { + border-color: #93c5fd; + background: #f8fbff; +} + +.question-option:disabled { + opacity: 1; + cursor: default; +} + +.question-option.question-option--correct { + border-color: #16a34a; + background: #dcfce7; + color: #166534; +} + +.question-option.question-option--incorrect { + border-color: #dc2626; + background: #fee2e2; + color: #991b1b; +} + +.lesson-actions { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.button { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 180px; + min-height: 50px; + padding: 0 20px; + border: 0; + border-radius: 18px; + background: #1d4ed8; + color: #ffffff; + text-decoration: none; + font-size: 0.96rem; + font-weight: 800; + cursor: pointer; +} + +.button:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.button--secondary { + background: #eff6ff; + color: #1d4ed8; +} + +.course-not-found { + min-height: 100vh; + display: grid; + place-items: center; + padding: 24px; +} + +.course-not-found__card { + max-width: 520px; + padding: 32px; + text-align: center; +} + +.course-not-found__card h1 { + margin: 0 0 12px; +} + +.course-not-found__card p { + margin: 0 0 20px; + color: #64748b; +} + +@media (max-width: 1024px) { + .learning-header__inner, + .learning-layout { + grid-template-columns: 1fr; + display: grid; + } + + .progress-card, + .sidebar-panel { + position: static; + } +} + +@media (max-width: 768px) { + .learning-header__inner, + .learning-layout { + padding-left: 20px; + padding-right: 20px; + } + + .learning-header__inner { + padding-top: 32px; + padding-bottom: 24px; + } + + .content-panel, + .sidebar-panel, + .course-not-found__card { + border-radius: 22px; + } + + .content-panel { + padding: 22px; + } + + .content-panel__header, + .lesson-actions, + .presentation-viewer__header, + .presentation-viewer__actions { + flex-direction: column; + align-items: stretch; + } + + .resource-download-card { + align-items: flex-start; + flex-direction: column; + } + + .resource-download-card__action { + width: 100%; + } +} diff --git a/src/app/course-learning-page/course-learning-page.html b/src/app/course-learning-page/course-learning-page.html new file mode 100644 index 00000000..ea1d9237 --- /dev/null +++ b/src/app/course-learning-page/course-learning-page.html @@ -0,0 +1,289 @@ + +
+
+
+
+ Voltar aos detalhes do curso + +

{{ course.title }}

+
+
+
+ +
+ + +
+
+
+
+ Percurso da Formação +

Contextualização

+
+
+ +

{{ course.summary }}

+ +
    +
  • {{ topic }}
  • +
+ +
+
+
+ Módulo {{ index + 1 + " " + item.module.title }} + {{ item.module.duration }} +
+ +
+

+ +
    +
  • + {{ bullet }} +
  • +
+ +

+ + Imagem da secao + +

+ +
    +
  • + {{ bullet }} +
  • +
+ +

+ +
    +
  • + {{ bullet }} +
  • +
+ +

+ + Imagem da secao + +

+ +
    +
  • + {{ bullet }} +
  • +
+ + Imagem da secao + +
+
+
+ Apresentação interativa +
+ + Imagem {{ getPresentationImageIndex(index) + 1 }} / {{ section.presentationImages!.length }} + +
+ +
+ Imagem da apresentacao +
+ +
+ + +
+
+
+
+
+
+ + + + + {{ course.pdfTitle ?? 'Documento PDF' }} + + + Download + + +
+
+
+ Validação de Conhecimentos +
+
+ +
+
+ Pergunta {{ index + 1 }} +

{{ question.prompt }}

+ +
+ +
+ +

{{ question.note }}

+
+
+
+ +
+ Voltar ao curso + +
+
+
+
+
+ +
+
+
+ + + {{ zoomedImageIndex() + 1 }} / {{ zoomedImageSet().length }} + + + + + + +
+
+ Imagem ampliada +
+
+
+ + +
+
+

Percurso nao encontrado

+

O percurso pedido nao esta disponivel neste momento.

+ Voltar aos cursos +
+
+
diff --git a/src/app/course-learning-page/course-learning-page.ts b/src/app/course-learning-page/course-learning-page.ts new file mode 100644 index 00000000..30c52424 --- /dev/null +++ b/src/app/course-learning-page/course-learning-page.ts @@ -0,0 +1,298 @@ +import { CommonModule } from '@angular/common'; +import { Component, HostListener, computed, effect, inject, signal } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { ActivatedRoute, RouterLink } from '@angular/router'; +import { CourseQuestion, getCourseBySlug } from '../data/courses'; + +@Component({ + selector: 'app-course-learning-page', + standalone: true, + imports: [CommonModule, RouterLink], + templateUrl: './course-learning-page.html', + styleUrl: './course-learning-page.css' +}) +export class CourseLearningPageComponent { + private static readonly QUESTIONS_PER_SESSION = 5; + private static readonly MIN_ZOOM_SCALE = 1; + private static readonly MAX_ZOOM_SCALE = 3; + private static readonly ZOOM_STEP = 0.25; + private readonly route = inject(ActivatedRoute); + private readonly paramMap = toSignal(this.route.paramMap); + private readonly selectedAnswers = signal>({}); + private readonly presentationImageIndexes = signal>({}); + readonly visibleQuestions = signal([]); + readonly currentModuleIndex = signal(0); + readonly zoomedImageSet = signal([]); + readonly zoomedImageIndex = signal(0); + readonly zoomedImageSrc = computed(() => this.zoomedImageSet()[this.zoomedImageIndex()] ?? null); + readonly zoomScale = signal(1); + readonly zoomOrigin = signal('50% 50%'); + private readonly resetAnswersOnCourseChange = effect(() => { + const slug = this.paramMap()?.get('slug') ?? null; + const course = getCourseBySlug(slug); + this.selectedAnswers.set({}); + this.presentationImageIndexes.set({}); + this.currentModuleIndex.set(0); + this.zoomedImageSet.set([]); + this.zoomedImageIndex.set(0); + this.zoomScale.set(1); + this.zoomOrigin.set('50% 50%'); + this.visibleQuestions.set(this.pickRandomQuestions(course?.questions ?? [])); + setTimeout(() => this.updateCurrentModuleFromScroll(), 0); + }); + + readonly course = computed(() => { + const slug = this.paramMap()?.get('slug') ?? null; + return getCourseBySlug(slug); + }); + + readonly modulesWithSections = computed(() => { + const course = this.course(); + if (!course) { + return []; + } + + const fallbackSection = course.lessonSections[course.lessonSections.length - 1] ?? null; + return course.modules.map((module, index) => ({ + module, + section: course.lessonSections[index] ?? fallbackSection + })); + }); + + readonly progressLabel = computed(() => { + const course = this.course(); + if (!course) { + return '0% complete'; + } + + return `${this.currentModuleIndex() + 1} of ${course.modules.length} módulos`; + }); + + readonly progressPercentage = computed(() => { + const course = this.course(); + if (!course || course.modules.length === 0) { + return 0; + } + + return ((this.currentModuleIndex() + 1) / course.modules.length) * 100; + }); + + scrollToModule(index: number): void { + const section = document.querySelector(`[data-module-index="${index}"]`); + if (!section) { + return; + } + + section.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + } + + @HostListener('window:scroll') + onWindowScroll(): void { + this.updateCurrentModuleFromScroll(); + } + + @HostListener('window:keydown.escape') + onEscapeKey(): void { + this.closeZoomedImage(); + } + + @HostListener('window:keydown.arrowleft') + onArrowLeftKey(): void { + this.showPreviousZoomedImage(); + } + + @HostListener('window:keydown.arrowright') + onArrowRightKey(): void { + this.showNextZoomedImage(); + } + + private updateCurrentModuleFromScroll(): void { + const sections = Array.from(document.querySelectorAll('[data-module-index]')); + if (sections.length === 0) { + return; + } + + const scrollProbe = window.scrollY + window.innerHeight * 0.35; + let activeIndex = 0; + + sections.forEach((section, index) => { + if (section.offsetTop <= scrollProbe) { + activeIndex = index; + } + }); + + if (activeIndex !== this.currentModuleIndex()) { + this.currentModuleIndex.set(activeIndex); + } + } + + selectAnswer(questionIndex: number, optionIndex: number): void { + const currentAnswers = this.selectedAnswers(); + if (currentAnswers[questionIndex] !== undefined) { + return; + } + + this.selectedAnswers.set({ + ...currentAnswers, + [questionIndex]: optionIndex + }); + } + + isQuestionAnswered(questionIndex: number): boolean { + return this.selectedAnswers()[questionIndex] !== undefined; + } + + isCorrectOption(questionIndex: number, optionIndex: number): boolean { + const question = this.visibleQuestions()[questionIndex]; + if (!question || !this.isQuestionAnswered(questionIndex)) { + return false; + } + + return question.correctOptionIndex === optionIndex; + } + + isWrongSelectedOption(questionIndex: number, optionIndex: number): boolean { + const selectedOption = this.selectedAnswers()[questionIndex]; + if (selectedOption === undefined) { + return false; + } + + const question = this.visibleQuestions()[questionIndex]; + if (!question) { + return false; + } + + const correctOption = question.correctOptionIndex; + return selectedOption === optionIndex && selectedOption !== correctOption; + } + + openZoomedImage(imageSrc: string): void { + this.openZoomedImageGallery([imageSrc], 0); + } + + openZoomedImageGallery(imageSet: string[], imageIndex: number): void { + this.zoomedImageSet.set(imageSet); + this.zoomedImageIndex.set(imageIndex); + this.zoomScale.set(1); + this.zoomOrigin.set('50% 50%'); + } + + closeZoomedImage(): void { + this.zoomedImageSet.set([]); + this.zoomedImageIndex.set(0); + this.zoomScale.set(1); + this.zoomOrigin.set('50% 50%'); + } + + showPreviousZoomedImage(): void { + const imageSet = this.zoomedImageSet(); + const imageIndex = this.zoomedImageIndex(); + if (imageSet.length <= 1 || imageIndex === 0) { + return; + } + + this.zoomedImageIndex.set(imageIndex - 1); + this.resetImageZoom(); + } + + showNextZoomedImage(): void { + const imageSet = this.zoomedImageSet(); + const imageIndex = this.zoomedImageIndex(); + if (imageSet.length <= 1 || imageIndex >= imageSet.length - 1) { + return; + } + + this.zoomedImageIndex.set(imageIndex + 1); + this.resetImageZoom(); + } + + previousPresentationImage(moduleIndex: number): void { + const currentImage = this.getPresentationImageIndex(moduleIndex); + if (currentImage === 0) { + return; + } + + this.presentationImageIndexes.update((indexes) => ({ + ...indexes, + [moduleIndex]: currentImage - 1 + })); + } + + nextPresentationImage(moduleIndex: number, images: string[]): void { + const currentImage = this.getPresentationImageIndex(moduleIndex); + if (currentImage >= images.length - 1) { + return; + } + + this.presentationImageIndexes.update((indexes) => ({ + ...indexes, + [moduleIndex]: currentImage + 1 + })); + } + + getPresentationImage(moduleIndex: number, images: string[]): string { + return images[this.getPresentationImageIndex(moduleIndex)] ?? images[0] ?? ''; + } + + getPresentationImageIndex(moduleIndex: number): number { + return this.presentationImageIndexes()[moduleIndex] ?? 0; + } + + zoomInImage(): void { + this.zoomScale.update((scale) => Math.min(scale + CourseLearningPageComponent.ZOOM_STEP, CourseLearningPageComponent.MAX_ZOOM_SCALE)); + } + + zoomOutImage(): void { + this.zoomScale.update((scale) => Math.max(scale - CourseLearningPageComponent.ZOOM_STEP, CourseLearningPageComponent.MIN_ZOOM_SCALE)); + } + + resetImageZoom(): void { + this.zoomScale.set(1); + this.zoomOrigin.set('50% 50%'); + } + + handleImageZoomWheel(event: WheelEvent, imageElement: HTMLImageElement): void { + event.preventDefault(); + this.updateZoomOriginFromPointer(event, imageElement); + + if (event.deltaY < 0) { + this.zoomInImage(); + return; + } + + this.zoomOutImage(); + } + + handleImageZoomClick(event: MouseEvent, imageElement: HTMLImageElement): void { + this.updateZoomOriginFromPointer(event, imageElement); + this.zoomInImage(); + } + + private updateZoomOriginFromPointer(event: MouseEvent | WheelEvent, imageElement: HTMLImageElement): void { + const bounds = imageElement.getBoundingClientRect(); + if (bounds.width === 0 || bounds.height === 0) { + return; + } + + const relativeX = ((event.clientX - bounds.left) / bounds.width) * 100; + const relativeY = ((event.clientY - bounds.top) / bounds.height) * 100; + const clampedX = Math.min(Math.max(relativeX, 0), 100); + const clampedY = Math.min(Math.max(relativeY, 0), 100); + + this.zoomOrigin.set(`${clampedX}% ${clampedY}%`); + } + + private pickRandomQuestions(questions: CourseQuestion[]): CourseQuestion[] { + const shuffledQuestions = [...questions]; + + for (let index = shuffledQuestions.length - 1; index > 0; index -= 1) { + const randomIndex = Math.floor(Math.random() * (index + 1)); + [shuffledQuestions[index], shuffledQuestions[randomIndex]] = [shuffledQuestions[randomIndex], shuffledQuestions[index]]; + } + + return shuffledQuestions.slice(0, CourseLearningPageComponent.QUESTIONS_PER_SESSION); + } +} diff --git a/src/app/data/courses.ts b/src/app/data/courses.ts new file mode 100644 index 00000000..87b69e24 --- /dev/null +++ b/src/app/data/courses.ts @@ -0,0 +1,1271 @@ +export interface CourseModule { + title: string; + duration: string; + description: string; +} + +export interface CourseLessonSection { + title: string; + paragraphs: string[]; + bullets?:string[]; + bullets2?:string[]; + bullets3?:string[]; + bullets4?:string[]; + paragraphs2: string[]; + paragraphs3: string[]; + paragraphs4: string[]; + paragraphs5: string[]; + paragraphs6?: string[]; + imagem?:string; + imagem2?:string; + imagem3?:string; + presentationImages?: string[]; +} + +export interface CourseQuestion { + prompt: string; + options: string[]; + note: string; + correctOptionIndex: number; +} + +export interface Course { + slug: string; + category: string; + categoryIcons: string[]; + title: string; + description: string; + summary: string; + topics: any; + level: string; + duration: string; + language: string; + format: string; + image: string; + focusAreas: string[]; + prerequisites: string[]; + audience: string[]; + objectives: string[]; + outcomes: string[]; + pdfPath?: string; + pdfTitle?: string; + pdfDescription?: string; + pdfDownloadName?: string; + pdfPath2?: string; + pdfTitle2?: string; + pdfDescription2?: string; + pdfDownloadName2?: string; + modules: CourseModule[]; + lessonSections: CourseLessonSection[]; + questions: CourseQuestion[]; +} + +export const COURSES: Course[] = [ + { + slug: 'formacao-plataforma', + category: 'Formacao', + categoryIcons: [ + '/categorias/extratos.svg', + '/categorias/reconciliacoes-bancarias.svg', + '/categorias/contabilizacoes.svg', + '/categorias/tesouraria.svg' + + ], + title: 'Metacase Learning Hub', + description: 'Tutorial de funcionamento da plataforma das formações base do ecosistema TargetOne.', + summary: 'O Metacase Learning Hub é a plataforma oficial de aprendizagem e capacitação dedicada ao ecossistema Target One, concebida para apoiar utilizadores, parceiros e equipas técnicas no domínio completo das funcionalidades, processos e boas práticas associadas a este programa.\nA plataforma Target One, desenvolvida pela MetaCase, constitui um conjunto de componentes especializados destinados à gestão integrada dos fluxos financeiros das organizações, permitindo centralizar operações, automatizar processos e fornecer informação fiável para suporte à tomada de decisão. Neste contexto, o Metacase Learning Hub surge como um ambiente digital estruturado de formação contínua que reúne conteúdos programáticos, cursos especializados e recursos técnicos que permitem compreender e explorar todo o potencial da plataforma Target One.\n Inspirado nos modelos de academias tecnológicas globais, o Metacase Learning Hub funciona como um repositório centralizado de conhecimento.', + topics: [ + 'Gestão de fluxos financeiros', + 'Reconciliações bancárias', + 'Gestão de pagamentos e cobranças', + 'Integração com sistemas ERP', + 'Previsão de tesouraria e liquidez', + 'Processos operacionais, estratégicos e de controlo financeiro' + ], + + level: 'Iniciante', + duration: '1h 00min', + language: 'Português', + format: 'Autónomo', + image: 'imagenscursos/learninghub.png', + focusAreas: [ + 'Navegacao da plataforma', + 'Pesquisa e filtros', + 'Operacoes do dia a dia' + ], + prerequisites: [ + 'Nenhum' + ], + audience: [ + 'Todos os utilizadores' + ], + objectives: [ + 'Conhecer a plataforma da Metacase Learning Hub', + 'Iniciar a formação', + 'Validar conhecimentos' + ], + outcomes: [ + 'Compreensao do fluxo base de trabalho', + 'Autonomia para consultas e operacoes simples', + 'Conhecimento das melhores praticas de utilizacao' + ], + modules: [ + { + title: 'Visão geral da plataforma', + duration: '15 min', + description: 'Mapa funcional da aplicação Metacase Learning Hub.' + }, + { + title: 'Detalhe das páginas da formação', + duration: '20 min', + description: 'Descrição da formação, desde competências a adquirir objetivos específicos da mesma e tempo de duração.' + }, + { + title: 'Estrutura das formações', + duration: '10 min', + description: 'Execução das formações per si, divisão de conteúdos programáticos, desde texto a interações de vídeo.' + }, + { + title: 'Perguntas de validação', + duration: '15 min', + description: 'Detalhe dos vários tipos de perguntas de cariz validativo, que podem complementar a formação.' + } + ], + lessonSections: [ + { + title: 'Visão geral da plataforma', + paragraphs: [ + 'Aprendizagem estruturada e orientada à prática\n\n O Metacase Learning Hub foi concebido para proporcionar uma experiência de aprendizagem progressiva e prática. Cada curso aborda cenários reais de utilização do Target One, permitindo aos participantes compreender não apenas as funcionalidades técnicas da plataforma, mas também os processos de negócio que esta suporta. \n A organização dos conteúdos segue uma lógica modular, permitindo que cada utilizador construa o seu próprio percurso de aprendizagem, evoluindo desde conceitos fundamentais até níveis mais avançados de configuração, integração e otimização de processos.\n\n Capacitação para utilizadores, parceiros e especialistas \n\n A plataforma desempenha também um papel estratégico no onboarding e capacitação de novos utilizadores e parceiros, garantindo que todas as equipas que trabalham com o Target One possuem um entendimento consistente da arquitetura, das funcionalidades e das melhores práticas de utilização. Ao consolidar conhecimento, documentação e formação num único ambiente digital, o Metacase Learning Hub promove:' + ], + bullets: [ + 'Maior autonomia dos utilizadores na operação da plataforma', + 'Maior rapidez na adoção de novas funcionalidades', + 'Padronização de processos e boas práticas', + 'Desenvolvimento contínuo de competências no ecossistema Target One' + ], + paragraphs2: [ + 'Um centro de conhecimento para inovação financeira\n\n Mais do que um simples portal de formação, o Metacase Learning Hub posiciona-se como um centro de conhecimento e capacitação tecnológica, permitindo que organizações e profissionais tirem o máximo partido das capacidades da plataforma Target One e das soluções de gestão de fluxos financeiros desenvolvidas pela MetaCase. Ao combinar aprendizagem estruturada, conteúdos técnicos especializados e uma abordagem orientada à prática, o Metacase Learning Hub contribui para acelerar a adoção do Target One e para maximizar o valor que esta plataforma pode trazer à gestão financeira das organizações.\n\n' + ], + imagem: '/screenshots/Pagina Principal.jpg', + paragraphs3: [ + ''], + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Detalhe das páginas da formação', + paragraphs: [ + 'O Metacase Learning Hub é estruturado, na sua base, como uma biblioteca centralizada de cursos, apresentados na página principal da plataforma. Estes cursos representam componentes essenciais para a correta utilização e compreensão do ecossistema TargetOne, reunindo conteúdos formativos que abordam os principais processos, funcionalidades e contextos operacionais associados à plataforma. \n Cada curso encontra-se representado através de um cartão informativo, onde é disponibilizada uma descrição sucinta do conteúdo formativo, a área temática a que se refere e a respetiva duração estimada em horas. O acesso a cada formação é efetuado através do botão “Entrar”, disponível em cada cartão, permitindo ao utilizador iniciar diretamente o percurso de aprendizagem associado ao curso selecionado. \n Esta abordagem permite organizar os conteúdos de forma clara e intuitiva, facilitando a navegação e o acesso rápido às diferentes formações disponíveis no portal.'], + paragraphs2: ['Adicionalmente, no canto superior direito da interface, encontra-se disponibilizado um link de acesso rápido para a página principal da MetaCase, permitindo aos utilizadores navegar facilmente entre o portal de formação e o website institucional da empresa. Esta funcionalidade reforça a integração do Metacase Learning Hub no ecossistema digital da organização e facilita o acesso a informação adicional sobre a empresa, os seus produtos e as soluções associadas à plataforma TargetOne.\n\n'], + paragraphs3: ['Ao aceder a um curso através do botão “Entrar”, o utilizador é direcionado para a página de descrição do curso selecionado, onde são apresentadas as informações essenciais sobre a formação e a respetiva estrutura de conteúdos. Esta página encontra-se organizada numa estrutura bipartida verticalmente, permitindo separar de forma clara a informação geral da formação da descrição detalhada dos seus conteúdos.\n\n Primeira secção – Informação geral da formação\n Na primeira área da página (visível na parte superior da interface), é apresentada uma visão geral do curso, incluindo a sua designação, uma descrição introdutória e os principais elementos informativos associados à formação.'], + bullets2: [ + 'Descrição geral da formação, que contextualiza o objetivo do curso e a sua relação com o ecossistema TargetOne;', + 'Duração total estimada, permitindo ao utilizador compreender o tempo necessário para concluir a formação;', + 'Formato da formação, indicando se o percurso é realizado de forma Autónoma, Instructor-led, Live Online, Blended Learning, Microlearning ou ainda Certificação;', + 'Número total de módulos que compõem o curso.' + ], + paragraphs4: ['Adicionalmente, é disponibilizado um bloco de informação complementar da formação, onde são apresentados:'], + bullets3: [ + 'Nível de dificuldade do curso;', + 'Idioma em que a formação é disponibilizada;', + 'Formato de aprendizagem;.', + 'Pré-requisitos necessários para frequentar o curso;', + 'Público-alvo a quem a formação se destina.', + ], + paragraphs5: ['Nesta mesma área encontra-se também um painel lateral de ação, que permite ao utilizador iniciar diretamente a formação através do botão “Iniciar formação”, bem como regressar rapidamente ao menu principal das formações.\n\n'], + imagem:"/screenshots/Descricaopgprincipal.jpg", + imagem2:"/screenshots/detalhecurso.jpg", + bullets4: [ + 'Título do módulo;', + 'Breve descrição do conteúdo abordado;', + 'Duração estimada de cada unidade;.', + 'competências a adequirir.' + ], + imagem3:"/screenshots/detalhecurso2.jpg", + paragraphs6: ['\n Segunda secção – Estrutura e competências da formação\nNa segunda parte da página é apresentada uma descrição mais detalhada da estrutura pedagógica da formação, permitindo ao utilizador compreender de forma clara os conteúdos que serão abordados ao longo da formação. Adicionalmente na coluna direita são apesentadas as competências expectáveis de serem adequiridas no final da formação.\n Nesta área é exibida a estrutura da formação, organizada por lições ou módulos, onde cada unidade apresenta:'] + }, + + { + title: 'Estrutura das formações', + paragraphs: [ + 'Ao iniciar uma formação, o utilizador é direcionado para a página principal do curso, que foi desenvolvida com base numa Single Page Application (SPA). Esta abordagem permite que todos os conteúdos da formação sejam apresentados de forma contínua e fluida, sem necessidade de navegar entre múltiplas páginas. \n A formação inicia-se com uma secção de contextualização dos temas, onde é apresentado o enquadramento geral do curso, seguindo-se posteriormente os módulos específicos que compõem o percurso formativo. \n A navegação entre os diferentes módulos pode ser realizada através de duas formas complementares. Por um lado, existe um menu lateral localizado no lado esquerdo da interface, que permite ao formando aceder diretamente aos diferentes módulos da formação. Por outro lado, é disponibilizada uma barra de progressão situada na parte superior direita da página, que permite acompanhar o progresso ao longo do curso e facilitar a navegação entre as diferentes secções. \n A Single Page Application foi concebida para proporcionar uma experiência de aprendizagem sequencial e intuitiva, permitindo que o formando percorra os conteúdos de forma contínua. Assim, o utilizador pode simplesmente avançar na leitura da formação, uma vez que os módulos foram organizados de forma sequencial e lógica, acompanhando a progressão natural dos temas abordados ao longo do curso.\n\n' + ], + paragraphs2: [], + paragraphs3: ['As imagens, gráficos e organigramas apresentados ao longo das formações são interativos, permitindo ao utilizador visualizar os conteúdos com maior detalhe. Para tal, basta clicar sobre o elemento pretendido, sendo automaticamente aberta uma visualização ampliada. \n Nesta visualização, é disponibilizado no canto superior um conjunto de ferramentas de interação, que permitem ao utilizador explorar o conteúdo apresentado. Entre estas funcionalidades incluem-se, por exemplo, opções de zoom, que permitem ampliar ou reduzir a imagem para uma melhor análise, bem como o botão de fecho, que possibilita regressar facilmente à página da formação.'], + paragraphs4: [ + ''], + imagem: '/screenshots/Curso.jpg', + imagem2: '/screenshots/Curso1.2.jpg', + paragraphs5: [ + 'Para além dos videos, imagens e conteúdo interativo, existe ainda as apresentações interativas. Estas apresentações têm a finalidade de permitir ao utilizar navegar entre um conjunto de informação disponivel sobre uma matéria e funciona da mesma forma que o explicado anteriormente para as imagens. Adicionalmente nestes casos quando estas apresentações interativas surgem nos módulos, permitem ao utilizador passar entre informação através de dois botões de "Seguinte" para passar para o proximo slide e de "Anterior" para voltar ao slide anterior. No caso de o user quiser apenas o foco nestes slides basta clicar na imagem da apresentação que esta foca o conteudo e os botões de navegação passam para o canto superior direito junto ao zoom e ao botão de fechar já lá existentes.'], + presentationImages: [ + '/screenshots/Curso1.3.jpg', + '/screenshots/Curso1.4.jpg', + ], + }, + + { + title: 'Perguntas de validação', + paragraphs: ['No final de cada módulo encontra-se disponibilizada uma secção dedicada à validação de conhecimentos, destinada a avaliar a compreensão dos conteúdos abordados ao longo do módulo. Esta avaliação é realizada através de um conjunto de perguntas de escolha múltipla, sendo apresentadas três opções de resposta para cada questão, das quais apenas uma é correta. \n As perguntas são selecionadas a partir de uma pool de questões associadas à formação, permitindo que estas variem entre diferentes tentativas. Desta forma, caso o formando repita o curso ou volte a realizar a avaliação, a probabilidade de encontrar exatamente as mesmas perguntas é reduzida, contribuindo para uma avaliação mais consistente dos conhecimentos adquiridos. \n Adicionalmente, nos cursos que incluem mecanismos de certificação, encontra-se definido um limiar mínimo de aprovação de 80% de respostas corretas. Caso o formando não atinja este valor, o curso não poderá ser concluído, sendo apresentada apenas a opção de repetir a formação. Por outro lado, caso o formando obtenha uma pontuação igual ou superior a 80% de respostas corretas, a formação é considerada concluída, ficando disponível a opção de finalizar o curso. \n Atualmente, todas as formações estão configuradas para apresentar cinco perguntas no momento de validação final, sendo estas selecionadas e apresentadas de forma aleatória a partir da pool de questões definida para cada curso.'], + paragraphs2: ['A resposta às perguntas de validação de conhecimentos é realizada através da seleção da opção que o formando considera correta. Após a escolha da resposta, o sistema fornece feedback imediato, informando se a resposta selecionada está correta ou incorreta.\n Caso a resposta esteja correta, a opção escolhida é destacada com um contorno verde, indicando que a seleção foi acertada. Por outro lado, se a resposta estiver incorreta, a opção selecionada pelo formando é assinalada a vermelho, sendo simultaneamente destacada a verde a opção correspondente à resposta correta, permitindo assim ao utilizador identificar imediatamente a solução correta para a questão apresentada.\n\n'], + paragraphs3: [], + paragraphs4: [ + ''], + imagem: '/screenshots/Curso2.jpg', + paragraphs5: [ + ''] + }, + + ], + questions: [ + { + prompt: 'Qual das seguintes áreas faz parte das funcionalidades abordadas na plataforma Target One?', + options: [ + 'Gestão de redes sociais corporativas.', + 'Gestão de fluxos financeiros.', + 'Desenvolvimento de aplicações móveis para clientes.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + }, + { + prompt: 'Qual é o principal objetivo do Metacase Learning Hub?', + options: [ + 'Servir apenas como repositório de documentação técnica do Target One.', + 'Substituir completamente os sistemas ERP utilizados pelas organizações.', + 'Disponibilizar uma plataforma de aprendizagem e capacitação para utilizadores, parceiros e equipas técnicas que trabalham com o ecossistema Target One.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 2 + }, + { + prompt: 'Qual é o principal objetivo do Metacase Learning Hub?', + options: [ + 'Servir como plataforma de gestão financeira para empresas.', + 'Centralizar conteúdos formativos e capacitar utilizadores no ecossistema TargetOne.', + 'Substituir o website institucional da MetaCase.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 2 + }, + { + prompt: 'Como são apresentados os cursos na página principal da plataforma?', + options: [ + 'Através de cartões informativos com descrição, tema e duração da formação.', + 'Através de listas técnicas sem qualquer descrição.', + 'Através de documentos PDF descarregáveis.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + }, + { + prompt: 'O que acontece quando o utilizador seleciona o botão “Entrar” num curso?', + options: [ + 'É direcionado para a página de descrição detalhada da formação selecionada.', + 'É automaticamente inscrito em todas as formações disponíveis.', + 'É redirecionado para o website institucional da MetaCase.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'Como está organizada a página de descrição de um curso?', + options: [ + 'Em três áreas independentes sem ligação entre si.', + 'Numa estrutura bipartida que separa informação geral da estrutura da formação.', + 'Apenas numa lista simples de módulos.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 2 + }, + { + prompt: 'De que forma o utilizador pode navegar entre os módulos da formação?', + options: [ + 'Apenas através do botão “voltar atrás” do navegador.', + 'Através do menu lateral e da barra de progressão da formação.', + 'Apenas utilizando um motor de pesquisa interno.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 2 + } + + ] + }, + + { + slug: 'Target One', + category: 'Formacao', + categoryIcons: [ + '/categorias/operacoes-financeiras.svg', + '/categorias/tesouraria.svg', + '/categorias/reconciliacoes-bancarias.svg' + ], + pdfPath: '/Powerpoints/Manual%20Metacase.pdf', + pdfTitle: 'Manual Apresentação Target One', + pdfDescription: 'Manual Apresentação Target One', + pdfDownloadName: 'Manual Metacase.pdf', + title: 'Target One', + description: 'Descriminação completa da plataforma base, para novos utilizadores.', + summary: 'A Plataforma Target One, desenvolvida pela MetaCase, é uma solução integrada para a gestão e controlo dos fluxos financeiros de empresas e grupos empresariais. Através da centralização da informação financeira e da integração com ERPs, sistemas internos e instituições financeiras, permite apoiar a tomada de decisão com dados fiáveis em tempo real. O seu ecossistema é composto por diversas componentes interligadas que suportam processos essenciais de tesouraria, pagamentos, reconciliações e operações financeiras, garantindo eficiência, segurança e escalabilidade na gestão financeira das organizações.', + topics: [], + level: 'Avancado', + duration: '55 min', + language: 'Portugues', + format: 'Autonomo', + image: '/imagenscursos/targetone.png', + focusAreas: [ + 'Plataforma Target One', + 'T Painel de Controlo', + 'T Parâmetros', + 'T Extratos', + 'T Reconciliações', + 'T Contabilização', + 'T Tesouraria', + 'T Pagamentos', + 'T Cobranças & Recebimentos', + 'T Caixas', + 'T Operações Financeiras', + 'T Orçamento', + ], + prerequisites: [ + 'Metacase Learning Hub', + 'Acesso ao Target One', + + ], + audience: [ + 'Todos', + + ], + objectives: [ + 'Compreender a plataforma Target One', + 'Entender as noções básicas das componentos do ecossistema Target One' + + ], + outcomes: [ + 'Maior dominio do fluxo financeiro', + 'Melhor leitura dos movimentos e extratos', + 'Mais rapidez no controlo e validacao diarios' + ], + modules: [ + { + title: 'Plataforma Target One', + duration: '5 min', + description: 'Explicação do programa Target One' + }, + { + title: 'Descrição das Componentes do Target One', + duration: '50 min', + description: 'Explicação das várias componentes da plataforma.' + }, + + ], + lessonSections: [ + { + title: 'TargetOne', + paragraphs: [ + 'A Target One é uma plataforma desenvolvida pela MetaCase para otimizar e controlar os fluxos financeiros de empresas e grupos, garantindo eficiência, segurança e integração com sistemas existentes. \n\nPrincipais vantagens:\n\n' + ], + paragraphs2: [''], + bullets: [ + 'Decisão informada com acesso a dados fiáveis em tempo real;', + 'Integração global com ERPs, sistemas internos e instituições financeiras;', + 'Segurança e auditoria (SOX Compliance) com histórico de alterações e controlo de acessos;', + 'Flexibilidade e escalabilidade, permitindo integrar novas funcionalidades conforme as necessidades do negócio;', + ], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Componentes TargetOne', + paragraphs: [ + 'O ecossistema TargetOne é constituído por um conjunto de componentes que suportam a gestão integrada dos fluxos financeiros, nomeadamente o Painel de Controlo, Parâmetros, Extratos, Reconciliações, Contabilização, Tesouraria, Pagamentos, Cobranças & Recebimentos, Caixas, Operações Financeiras e Operações de Orçamento.' + ], + paragraphs2: [], + presentationImages: [ + '/Powerpoints/TargetOne/Diapositivo1.PNG', + '/Powerpoints/TargetOne/Diapositivo2.PNG', + '/Powerpoints/TargetOne/Diapositivo3.PNG', + '/Powerpoints/TargetOne/Diapositivo4.PNG', + '/Powerpoints/TargetOne/Diapositivo5.PNG', + '/Powerpoints/TargetOne/Diapositivo6.PNG', + '/Powerpoints/TargetOne/Diapositivo7.PNG', + '/Powerpoints/TargetOne/Diapositivo8.PNG', + '/Powerpoints/TargetOne/Diapositivo9.PNG', + '/Powerpoints/TargetOne/Diapositivo10.PNG', + '/Powerpoints/TargetOne/Diapositivo11.PNG', + '/Powerpoints/TargetOne/Diapositivo12.PNG', + '/Powerpoints/TargetOne/Diapositivo13.PNG', + '/Powerpoints/TargetOne/Diapositivo1.PNG', + ], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Conhecimentos a consolidar', + paragraphs: [ + 'Usa esta secao para reforcar a interpretacao de desvios, excecoes e fecho diario.', + 'Se quiseres, mais tarde podes acrescentar imagens, tabelas ou exemplos de casos.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + } + ], + questions: [ + { + prompt: 'Qual é o principal objetivo da plataforma Target One?', + options: [ + 'Gerir exclusivamente recursos humanos das empresas.', + 'Permitir uma gestão eficaz, rigorosa e otimizada dos fluxos financeiros das empresas e grupos.', + 'Substituir completamente os sistemas ERP das empresas.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + }, + { + prompt: 'Uma das principais vantagens da plataforma Target One é:', + options: [ + 'Tomada de decisão baseada em informações fiáveis e em tempo útil.', + 'Substituição de todos os sistemas financeiros existentes.', + 'Gestão exclusiva de contas bancárias pessoais.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'A conectividade da plataforma Target One permite:', + options: [ + 'Integração com ERPs, sistemas das empresas e instituições financeiras.', + 'Ligação apenas a bases de dados locais.', + 'Ligação apenas a sistemas de contabilidade offline.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'Qual componente permite o acesso às várias funcionalidades da plataforma e a gestão de permissões?', + options: [ + 'Tesouraria', + 'Painel de Controlo', + 'Operações Financeiras' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + }, + { + prompt: 'O componente T Parâmetros é utilizado principalmente para:', + options: [ + 'Configuração e manutenção de cadastro transversal.', + 'Execução de pagamentos bancários.', + 'Criação de contratos financeiros.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'Qual componente permite a auditoria e gestão de informação dos extratos bancários?', + options: [ + 'Extratos', + 'Orçamento', + 'Caixas' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'A reconciliação bancária na plataforma Target One pode ser realizada de que forma?', + options: [ + 'Apenas manualmente.', + 'Automática e manual.', + 'Apenas através do ERP.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + }, + { + prompt: 'O módulo de Contabilização permite:', + options: [ + 'Classificação e contabilização automática de fluxos financeiros.', + 'Gestão de recursos humanos.', + 'Gestão de inventário.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'Qual componente permite obter uma visão global da posição de tesouraria da empresa?', + options: [ + 'Tesouraria', + 'Cobranças & Recebimentos', + 'Caixas' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'O módulo T Pagamentos permite:', + options: [ + 'Apenas visualizar saldos bancários.', + 'Criar, aprovar e enviar propostas de pagamento para os bancos.', + 'Gerir inventário de produtos.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + }, + { + prompt: 'Qual componente é responsável pela gestão de cobranças e recebimentos das empresas?', + options: [ + 'Cobranças & Recebimentos', + 'Tesouraria', + 'Parâmetros' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'O módulo T Caixas permite:', + options: [ + 'Gerir fechos de caixa e prestações de contas.', + 'Gerir contratos financeiros.', + 'Criar orçamentos financeiros.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'Qual componente permite gerir contratos associados a instrumentos financeiros?', + options: [ + 'Operações Financeiras', + 'Pagamentos', + 'Extratos' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'O módulo T Orçamento permite:', + options: [ + 'Gestão do orçamento de tesouraria e análise de desvios.', + 'Gestão de contas de clientes.', + 'Gestão de salários.' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 0 + }, + { + prompt: 'Qual funcionalidade permite acompanhar o estado das propostas enviadas aos bancos?', + options: [ + 'Reconciliações', + 'Pagamentos', + 'Parâmetros' + ], + note: 'Apenas uma resposta está certa', + correctOptionIndex: 1 + } + ] + }, + { + slug: 'T Extratos', + category: 'Extratos', + categoryIcons: [ + '/categorias/operacoes-financeiras.svg', + '/categorias/tesouraria.svg', + '/categorias/reconciliacoes-bancarias.svg' + ], + title: 'T Extratos', + description: 'Formação especifica para a componente de T Estratos do ecosistema Target One.', + summary: 'Formacao focada nas rotinas de tesouraria para utilizadores que precisam de acompanhar movimentos, validar consistencia e garantir controlo sobre o ciclo financeiro diario.', + topics: [], + level: 'Avancado', + duration: '7h 30min', + language: 'Portugues', + format: 'Autonomo', + image: '/imagenscursos/Extratos.png', + focusAreas: [ + 'Operacoes financeiras', + 'Movimentos e extratos', + 'Reconciliacao bancaria' + ], + prerequisites: [ + 'Acesso à Plataforma Target One', + 'Acesso à Componente T Extractos' + ], + audience: [ + 'Equipas de Extractos', + 'Clientes T Extratos', + ], + objectives: [ + 'Compreender o papel da Componente T Extractos', + 'Gestão e integração de extratos bancários', + 'Normalização de fluxos bancário', + 'Validação e controlo de extratos', + 'Auditoria e monitorização da informação bancária', + 'Utilização operacional da componente', + ], + outcomes: [ + 'Maior dominio do fluxo financeiro', + 'Melhor leitura dos movimentos e extratos', + 'Mais rapidez no controlo e validacao diarios' + ], + modules: [ + { + title: 'Contextualização da componente T Extractos', + duration: '5 min', + description: 'Explicação sumária da componente da formação.' + }, + { + title: 'Menus', + duration: '25 min', + description: 'Exploração dos menus bases existentes.' + }, + { + title: 'Funções Gerais da Componente', + duration: '30 min', + description: 'Explicação das Teclas de atalho, icons e funções das mesmas.' + }, + { + title: 'Outras Funcionalidades', + duration: '60 min', + description: 'Funcionalidades complementares dentro da componente T Extratos.' + }, + { + title: 'Receção de Extratos Bancários - Integração', + duration: '90 min', + description: 'Visualização de todos os extratos bancários através de diferentes modos de integração, e análise das diferentes situações.' + }, + { + title: 'Análises/Reports', + duration: '90 min', + description: 'Consulta e análise dos dados dos extratos bancários integrados no sistema.' + }, + { + title: 'Consulta de Estatísticas dos Extratos', + duration: '30 min', + description: 'Visualização de saldos médios por código de extrato.' + }, + { + title: 'Configuração - Aplicação', + duration: '90 min', + description: 'Aceder e configurar os parâmetros relacionados com a gestão de extratos bancários.' + } + ], + lessonSections: [ + { + title: 'Contextualização da componente T Extractos', + paragraphs: [ + 'A Componente T Extractos é especializada na auditoria, gestão e controlo de extratos bancários, independentemente das instituições financeiras com as quais a sociedade ou grupo empresarial opere.', + 'Os extratos bancários podem ser integrados na plataforma através de diferentes origens, nomeadamente:.' + ], + bullets: [ + 'Receção através do Canal Multibancário', + 'Importação através de template Excel', + 'Inserção manual de extratos' + ], + paragraphs2: [], + paragraphs3: ['Todos os extratos integrados são armazenados na plataforma por período ilimitado, permitindo a sua gestão, manutenção e consulta histórica através desta componente.Nesta componente são também definidas codificações e descrições personalizadas, designadas por Códigos de Extrato. Estes códigos podem ser associados à informação presente nas operações de cada extrato bancário, permitindo uniformizar e organizar os diferentes fluxos bancários. Esta normalização é particularmente relevante, uma vez que os mesmos tipos de movimentos podem apresentar códigos e descrições distintos entre diferentes instituições bancárias. \n Através desta codificação atribuída a cada movimento de extrato, é possível estruturar e normalizar a informação bancária, facilitando a análise, controlo e gestão dos fluxos financeiros.\n Adicionalmente, a componente integra mecanismos automáticos de validação e controlo dos extratos bancários, os quais verificam a sequencialidade dos saldos, a coerência das datas e a consistência do conteúdo de cada extrato. Estes mecanismos permitem identificar eventuais irregularidades, tais como extratos duplicados ou incoerentes, procedendo automaticamente à sua rejeição, garantindo assim a integridade e fiabilidade da informação registada na plataforma.'], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Menus', + paragraphs: [ + 'A Componente T Extractos disponibiliza um conjunto de menus que permitem ao utilizador executar as diferentes operações associadas à integração, consulta, análise e configuração de extratos bancários. \n O menu Integração permite efetuar a integração de extratos bancários na plataforma, bem como consultar o histórico das integrações realizadas e verificar o respetivo estado.\n No menu Análises/Reports, encontram-se disponíveis funcionalidades de consulta e análise dos extratos bancários integrados com sucesso. Neste menu é possível consultar os movimentos bancários por extrato, por tipo de movimento e/ou por intervalos de datas. Adicionalmente, é também através deste menu que se encontra disponível a funcionalidade de controlo de contas, permitindo acompanhar a evolução e consistência dos movimentos bancários. \n O menu Estatísticas disponibiliza ferramentas de análise estatística relacionadas com os extratos bancários. Neste menu é possível consultar informação agregada por código de extrato, bem como analisar saldos médios, permitindo uma visão consolidada da atividade bancária.\n Através do menu Configuração, o utilizador pode proceder à parametrização dos códigos de extrato, à inicialização de contas e à definição de outras configurações necessárias ao correto funcionamento da componente. \n O menu Janela apresenta a listagem de todas as janelas que se encontram abertas ou ativas na aplicação, permitindo ao utilizador alternar facilmente entre diferentes áreas de trabalho. \n Por fim, o menu Sair permite terminar a sessão na componente, encerrando a sua utilização na plataforma.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Conhecimentos a consolidar', + paragraphs: [ + 'Usa esta secao para reforcar a interpretacao de desvios, excecoes e fecho diario.', + 'Se quiseres, mais tarde podes acrescentar imagens, tabelas ou exemplos de casos.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + } + ], + questions: [ + { + prompt: 'Exemplo de pergunta 1: qual deve ser o foco principal na leitura de um extrato bancario nesta licao?', + options: [ + 'Validar movimentos e desvios', + 'Alterar a estrutura da conta', + 'Criar um novo utilizador' + ], + note: 'Substitui este texto com a explicacao da resposta certa.', + correctOptionIndex: 0 + }, + { + prompt: 'Exemplo de pergunta 2: o que pretendes confirmar antes do fecho diario?', + options: [ + 'Consistencia dos indicadores e pendentes', + 'Apenas a cor dos estados', + 'Somente a imagem do dashboard' + ], + note: 'Este bloco fica preparado para adicionares perguntas reais do percurso.', + correctOptionIndex: 0 + } + ] + }, + { + slug: 'T segurancas', + category: 'T segurancas', + categoryIcons: [ + '/categorias/reconciliacoes-bancarias.svg', + '/categorias/contabilizacoes.svg' + ], + title: 'T Seguranças', + description: 'Formacao especifica para a componente de T Seguranças do ecosistema Target One.', + summary: 'Percurso orientado a utilizadores que trabalham processos dedicados ao outsourcing EDP e precisam de dominar as validacoes, reconciliacoes e checkpoints do servico.', + topics: [], + level: 'Intermedio', + duration: '4h 10min', + language: 'Portugues', + format: 'Autonomo', + image: '/imagenscursos/Seguranças.png', + focusAreas: [ + 'Fluxos EDP', + 'Validacao operacional', + 'Controlo e reconciliacao' + ], + prerequisites: [ + 'Conhecimento basico da plataforma', + 'Acesso aos modulos operacionais do outsourcing', + 'Contexto funcional do processo EDP' + ], + audience: [ + 'Equipas de outsourcing', + 'Supervisores operacionais', + 'Elementos de controlo e suporte' + ], + objectives: [ + 'Executar o fluxo completo do outsourcing EDP', + 'Validar dados criticos antes de fecho', + 'Reconciliar diferencas operacionais', + 'Escalar desvios com a informacao certa' + ], + outcomes: [ + 'Maior consistencia na operacao diaria', + 'Reducao de erros na validacao', + 'Melhor visibilidade sobre os checkpoints do processo' + ], + modules: [ + { + title: 'Enquadramento do servico', + duration: '35 min', + description: 'Contexto do outsourcing EDP, responsabilidades e pontos de controlo ao longo do processo.' + }, + { + title: 'Operacao assistida', + duration: '65 min', + description: 'Execucao do fluxo principal na plataforma com os passos, regras e verificacoes associados.' + }, + { + title: 'Reconciliacao e controlo', + duration: '70 min', + description: 'Analise de divergencias, conciliacao de informacao e preparacao de evidencia de suporte.' + }, + { + title: 'Fecho e acompanhamento', + duration: '40 min', + description: 'Checklist final, tratamento de excecoes e registo de pontos pendentes para acompanhamento.' + } + ], + lessonSections: [ + { + title: 'Contexto do servico', + paragraphs: [ + 'Utiliza esta secao para explicar o enquadramento do outsourcing EDP, quem executa o processo e quais sao os checkpoints mais relevantes.', + 'O objetivo e que o formando entenda rapidamente em que parte do fluxo esta a trabalhar.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Execucao do fluxo', + paragraphs: [ + 'Aqui podes documentar o passo a passo do processo, incluindo validacoes, excecoes e evidencias a recolher.', + 'Este modelo foi deixado preparado para inserires instrucoes mais detalhadas e exemplos concretos.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Fecho e controlo', + paragraphs: [ + 'Reserva este bloco para orientacoes de fecho, reconciliacao e acompanhamento de pendentes.', + 'Tambem podes usar este espaco para notas internas, links ou referencias complementares.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + } + ], + questions: [ + { + prompt: 'Exemplo de pergunta 1: em que momento deve ser feita a validacao dos dados criticos do processo?', + options: [ + 'Antes do fecho operacional', + 'Apenas no dia seguinte', + 'Nao e necessaria validacao' + ], + note: 'Edita esta pergunta e adapta as opcoes ao processo real.', + correctOptionIndex: 0 + }, + { + prompt: 'Exemplo de pergunta 2: qual o objetivo da reconciliacao nesta operacao?', + options: [ + 'Confirmar consistencia e identificar desvios', + 'Alterar automaticamente os dados', + 'Eliminar registos sem validacao' + ], + note: 'Podes transformar este bloco num quiz, verdadeiro/falso ou checklist.', + correctOptionIndex: 0 + } + ] + }, + { + slug: 'T Parâmetros', + category: 'T Parâmetros', + categoryIcons: [ + '/categorias/reconciliacoes-bancarias.svg', + '/categorias/contabilizacoes.svg' + ], + title: 'T Parâmetros', + description: 'Formacao especifica para a componente de T Parâmetros do ecosistema Target One.', + summary: 'Percurso orientado a utilizadores que trabalham processos dedicados ao outsourcing EDP e precisam de dominar as validacoes, reconciliacoes e checkpoints do servico.', + topics: [], + level: 'Intermedio', + duration: '4h 10min', + language: 'Portugues', + format: 'Autonomo', + image: '/imagenscursos/Parametros.png', + focusAreas: [ + 'Fluxos EDP', + 'Validacao operacional', + 'Controlo e reconciliacao' + ], + prerequisites: [ + 'Conhecimento basico da plataforma', + 'Acesso aos modulos operacionais do outsourcing', + 'Contexto funcional do processo EDP' + ], + audience: [ + 'Equipas de outsourcing', + 'Supervisores operacionais', + 'Elementos de controlo e suporte' + ], + objectives: [ + 'Executar o fluxo completo do outsourcing EDP', + 'Validar dados criticos antes de fecho', + 'Reconciliar diferencas operacionais', + 'Escalar desvios com a informacao certa' + ], + outcomes: [ + 'Maior consistencia na operacao diaria', + 'Reducao de erros na validacao', + 'Melhor visibilidade sobre os checkpoints do processo' + ], + modules: [ + { + title: 'Enquadramento do servico', + duration: '35 min', + description: 'Contexto do outsourcing EDP, responsabilidades e pontos de controlo ao longo do processo.' + }, + { + title: 'Operacao assistida', + duration: '65 min', + description: 'Execucao do fluxo principal na plataforma com os passos, regras e verificacoes associados.' + }, + { + title: 'Reconciliacao e controlo', + duration: '70 min', + description: 'Analise de divergencias, conciliacao de informacao e preparacao de evidencia de suporte.' + }, + { + title: 'Fecho e acompanhamento', + duration: '40 min', + description: 'Checklist final, tratamento de excecoes e registo de pontos pendentes para acompanhamento.' + } + ], + lessonSections: [ + { + title: 'Contexto do servico', + paragraphs: [ + 'Utiliza esta secao para explicar o enquadramento do outsourcing EDP, quem executa o processo e quais sao os checkpoints mais relevantes.', + 'O objetivo e que o formando entenda rapidamente em que parte do fluxo esta a trabalhar.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Execucao do fluxo', + paragraphs: [ + 'Aqui podes documentar o passo a passo do processo, incluindo validacoes, excecoes e evidencias a recolher.', + 'Este modelo foi deixado preparado para inserires instrucoes mais detalhadas e exemplos concretos.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Fecho e controlo', + paragraphs: [ + 'Reserva este bloco para orientacoes de fecho, reconciliacao e acompanhamento de pendentes.', + 'Tambem podes usar este espaco para notas internas, links ou referencias complementares.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + } + ], + questions: [ + { + prompt: 'Exemplo de pergunta 1: em que momento deve ser feita a validacao dos dados criticos do processo?', + options: [ + 'Antes do fecho operacional', + 'Apenas no dia seguinte', + 'Nao e necessaria validacao' + ], + note: 'Edita esta pergunta e adapta as opcoes ao processo real.', + correctOptionIndex: 0 + }, + { + prompt: 'Exemplo de pergunta 2: qual o objetivo da reconciliacao nesta operacao?', + options: [ + 'Confirmar consistencia e identificar desvios', + 'Alterar automaticamente os dados', + 'Eliminar registos sem validacao' + ], + note: 'Podes transformar este bloco num quiz, verdadeiro/falso ou checklist.', + correctOptionIndex: 0 + } + ] + }, + { + slug: 'T Reconciliações', + category: 'Reconciliações', + categoryIcons: [ + '/categorias/reconciliacoes-bancarias.svg', + '/categorias/contabilizacoes.svg' + ], + title: 'T Reconciliações', + description: 'Formacao especifica para a operacao do outsourcing EDP e para os fluxos mais frequentes associados.', + summary: 'Percurso orientado a utilizadores que trabalham processos dedicados ao outsourcing EDP e precisam de dominar as validacoes, reconciliacoes e checkpoints do servico.', + topics: [], + level: 'Intermedio', + duration: '4h 10min', + language: 'Portugues', + format: 'Autonomo', + image: '/imagenscursos/reconciliacoes.png', + focusAreas: [ + 'Fluxos EDP', + 'Validacao operacional', + 'Controlo e reconciliacao' + ], + prerequisites: [ + 'Conhecimento basico da plataforma', + 'Acesso aos modulos operacionais do outsourcing', + 'Contexto funcional do processo EDP' + ], + audience: [ + 'Equipas de outsourcing', + 'Supervisores operacionais', + 'Elementos de controlo e suporte' + ], + objectives: [ + 'Executar o fluxo completo do outsourcing EDP', + 'Validar dados criticos antes de fecho', + 'Reconciliar diferencas operacionais', + 'Escalar desvios com a informacao certa' + ], + outcomes: [ + 'Maior consistencia na operacao diaria', + 'Reducao de erros na validacao', + 'Melhor visibilidade sobre os checkpoints do processo' + ], + modules: [ + { + title: 'Enquadramento do servico', + duration: '35 min', + description: 'Contexto do outsourcing EDP, responsabilidades e pontos de controlo ao longo do processo.' + }, + { + title: 'Operacao assistida', + duration: '65 min', + description: 'Execucao do fluxo principal na plataforma com os passos, regras e verificacoes associados.' + }, + { + title: 'Reconciliacao e controlo', + duration: '70 min', + description: 'Analise de divergencias, conciliacao de informacao e preparacao de evidencia de suporte.' + }, + { + title: 'Fecho e acompanhamento', + duration: '40 min', + description: 'Checklist final, tratamento de excecoes e registo de pontos pendentes para acompanhamento.' + } + ], + lessonSections: [ + { + title: 'Contexto do servico', + paragraphs: [ + 'Utiliza esta secao para explicar o enquadramento do outsourcing EDP, quem executa o processo e quais sao os checkpoints mais relevantes.', + 'O objetivo e que o formando entenda rapidamente em que parte do fluxo esta a trabalhar.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Execucao do fluxo', + paragraphs: [ + 'Aqui podes documentar o passo a passo do processo, incluindo validacoes, excecoes e evidencias a recolher.', + 'Este modelo foi deixado preparado para inserires instrucoes mais detalhadas e exemplos concretos.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Fecho e controlo', + paragraphs: [ + 'Reserva este bloco para orientacoes de fecho, reconciliacao e acompanhamento de pendentes.', + 'Tambem podes usar este espaco para notas internas, links ou referencias complementares.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + } + ], + questions: [ + { + prompt: 'Exemplo de pergunta 1: em que momento deve ser feita a validacao dos dados criticos do processo?', + options: [ + 'Antes do fecho operacional', + 'Apenas no dia seguinte', + 'Nao e necessaria validacao' + ], + note: 'Edita esta pergunta e adapta as opcoes ao processo real.', + correctOptionIndex: 0 + }, + { + prompt: 'Exemplo de pergunta 2: qual o objetivo da reconciliacao nesta operacao?', + options: [ + 'Confirmar consistencia e identificar desvios', + 'Alterar automaticamente os dados', + 'Eliminar registos sem validacao' + ], + note: 'Podes transformar este bloco num quiz, verdadeiro/falso ou checklist.', + correctOptionIndex: 0 + } + ] + }, + { + slug: 'outsourcing-edp', + category: 'Outsourcing EDP', + categoryIcons: [ + '/categorias/reconciliacoes-bancarias.svg', + '/categorias/contabilizacoes.svg' + ], + title: 'Outsourcing EDP', + description: 'Formacao especifica para a operacao do outsourcing EDP e para os fluxos mais frequentes associados.', + summary: 'Percurso orientado a utilizadores que trabalham processos dedicados ao outsourcing EDP e precisam de dominar as validacoes, reconciliacoes e checkpoints do servico.', + topics: [], + level: 'Intermedio', + duration: '4h 10min', + language: 'Portugues', + format: 'Autonomo', + image: '/imagenscursos/MetacaseSIbs.png', + focusAreas: [ + 'Fluxos EDP', + 'Validacao operacional', + 'Controlo e reconciliacao' + ], + prerequisites: [ + 'Conhecimento basico da plataforma', + 'Acesso aos modulos operacionais do outsourcing', + 'Contexto funcional do processo EDP' + ], + audience: [ + 'Equipas de outsourcing', + 'Supervisores operacionais', + 'Elementos de controlo e suporte' + ], + objectives: [ + 'Executar o fluxo completo do outsourcing EDP', + 'Validar dados criticos antes de fecho', + 'Reconciliar diferencas operacionais', + 'Escalar desvios com a informacao certa' + ], + outcomes: [ + 'Maior consistencia na operacao diaria', + 'Reducao de erros na validacao', + 'Melhor visibilidade sobre os checkpoints do processo' + ], + modules: [ + { + title: 'Enquadramento do servico', + duration: '35 min', + description: 'Contexto do outsourcing EDP, responsabilidades e pontos de controlo ao longo do processo.' + }, + { + title: 'Operacao assistida', + duration: '65 min', + description: 'Execucao do fluxo principal na plataforma com os passos, regras e verificacoes associados.' + }, + { + title: 'Reconciliacao e controlo', + duration: '70 min', + description: 'Analise de divergencias, conciliacao de informacao e preparacao de evidencia de suporte.' + }, + { + title: 'Fecho e acompanhamento', + duration: '40 min', + description: 'Checklist final, tratamento de excecoes e registo de pontos pendentes para acompanhamento.' + } + ], + lessonSections: [ + { + title: 'Contexto do servico', + paragraphs: [ + 'Utiliza esta secao para explicar o enquadramento do outsourcing EDP, quem executa o processo e quais sao os checkpoints mais relevantes.', + 'O objetivo e que o formando entenda rapidamente em que parte do fluxo esta a trabalhar.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Execucao do fluxo', + paragraphs: [ + 'Aqui podes documentar o passo a passo do processo, incluindo validacoes, excecoes e evidencias a recolher.', + 'Este modelo foi deixado preparado para inserires instrucoes mais detalhadas e exemplos concretos.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + }, + { + title: 'Fecho e controlo', + paragraphs: [ + 'Reserva este bloco para orientacoes de fecho, reconciliacao e acompanhamento de pendentes.', + 'Tambem podes usar este espaco para notas internas, links ou referencias complementares.' + ], + paragraphs2: [], + paragraphs3: [], + imagem: "", + paragraphs4: [ + ''], + paragraphs5: [ + ''] + } + ], + questions: [ + { + prompt: 'Exemplo de pergunta 1: em que momento deve ser feita a validacao dos dados criticos do processo?', + options: [ + 'Antes do fecho operacional', + 'Apenas no dia seguinte', + 'Nao e necessaria validacao' + ], + note: 'Edita esta pergunta e adapta as opcoes ao processo real.', + correctOptionIndex: 0 + }, + { + prompt: 'Exemplo de pergunta 2: qual o objetivo da reconciliacao nesta operacao?', + options: [ + 'Confirmar consistencia e identificar desvios', + 'Alterar automaticamente os dados', + 'Eliminar registos sem validacao' + ], + note: 'Podes transformar este bloco num quiz, verdadeiro/falso ou checklist.', + correctOptionIndex: 0 + } + ] + } + + +]; + +export function getCourseBySlug(slug: string | null): Course | null { + if (!slug) { + return null; + } + + return COURSES.find((course) => course.slug === slug) ?? null; +} diff --git a/src/app/formacaometacase/formacaometacase.css b/src/app/formacaometacase/formacaometacase.css new file mode 100644 index 00000000..53c76a9c --- /dev/null +++ b/src/app/formacaometacase/formacaometacase.css @@ -0,0 +1,57 @@ +.hero-logo-badge { + position: absolute; + top: 24px; + right: 24px; + z-index: 1; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 10px 16px; + border: 1px solid rgba(191, 219, 254, 0.55); + border-radius: 999px; + background: rgba(239, 246, 255, 0.88); + backdrop-filter: blur(8px); + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.12); +} + +.hero-logo { + width: clamp(120px, 16vw, 190px); + height: auto; + display: block; + object-fit: contain; +} + +.course-card__badge { + position: absolute; + top: 16px; + left: 16px; + z-index: 1; + display: flex; + align-items: center; + justify-content: flex-start; + gap: 8px; + max-width: calc(100% - 32px); + overflow-x: auto; +} + +.course-card__badge-image { + width: auto; + max-width: 88px; + flex: 0 0 auto; + height: 24px; + display: block; + object-fit: contain; +} + +@media (max-width: 768px) { + .hero-logo-badge { + top: 16px; + right: 16px; + padding: 8px 14px; + } + + .hero-logo { + width: 120px; + } + +} diff --git a/src/app/formacaometacase/formacaometacase.html b/src/app/formacaometacase/formacaometacase.html new file mode 100644 index 00000000..1057e1f2 --- /dev/null +++ b/src/app/formacaometacase/formacaometacase.html @@ -0,0 +1,98 @@ +
+
+
+
+ + + +
+ +
+
+ + Learning Hub + + +

+ Formações de TargetOne +

+ +

+ Formações práticas e atualizadas para a utilização da plataforma TargetOne
Aprendizagem orientada para a ferramenta com formações teóricas e práticas +

+
+
+
+ +
+
+
+

Formações disponíveis

+

+ Atualmente encontram-se disponíveis {{ courses.length }} {{ courses.length === 1 ? 'formação' : 'formações' }} em destaque. +

+
+ +
+ + {{ courses.length }} {{ courses.length === 1 ? 'curso' : 'cursos' }} + +
+
+
+ +
+
+
+
+ + +
+ +
+ +
+
+ +
+

+ {{ course.title }} +

+ +

+ {{ course.description }} +

+ +
+ + + {{ course.duration }} + +
+ + + Entrar + +
+
+
+
+
diff --git a/src/app/formacaometacase/formacaometacase.spec.ts b/src/app/formacaometacase/formacaometacase.spec.ts new file mode 100644 index 00000000..9c226f3c --- /dev/null +++ b/src/app/formacaometacase/formacaometacase.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; + +import { Formacaometacase } from './formacaometacase'; + +describe('Formacaometacase', () => { + let component: Formacaometacase; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [Formacaometacase], + providers: [provideRouter([])] + }).compileComponents(); + + fixture = TestBed.createComponent(Formacaometacase); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/formacaometacase/formacaometacase.ts b/src/app/formacaometacase/formacaometacase.ts new file mode 100644 index 00000000..9b726f7f --- /dev/null +++ b/src/app/formacaometacase/formacaometacase.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterLink } from '@angular/router'; +import { COURSES, type Course } from '../data/courses'; + +@Component({ + selector: 'app-formacaometacase', + standalone: true, + imports: [CommonModule, RouterLink], + templateUrl: './formacaometacase.html', + styleUrl: './formacaometacase.css' +}) +export class Formacaometacase { + readonly courses: Course[] = COURSES; +}