diff --git a/app/entry.server.tsx b/app/entry.server.tsx
index 6a5805e..c0c89a2 100644
--- a/app/entry.server.tsx
+++ b/app/entry.server.tsx
@@ -7,6 +7,8 @@ import { PassThrough } from 'stream'
import { getEnv, init } from './utils/env.server.ts'
import { NonceProvider } from './utils/nonce-provider.ts'
import { makeTimings } from './utils/timing.server.ts'
+//import { CronJob } from 'cron'
+//import { prisma } from './utils/db.server.ts'
const ABORT_DELAY = 5000
@@ -17,6 +19,22 @@ if (ENV.MODE === 'production' && ENV.SENTRY_DSN) {
import('~/utils/monitoring.server.ts').then(({ init }) => init())
}
+/* new CronJob(
+ '* * * * *', // cronTime
+ async function () {
+ const emailsToSend = await prisma.emailSchedule.findMany()
+ console.log(`${new Date().toTimeString()} There are now ${emailsToSend.length} emails on the queue...`)
+ //await sendEmail({
+ // to: user.email,
+ // subject: `André Casal Password Reset`,
+ // react: ,
+ //})
+ }, // onTick
+ null, // onComplete
+ true, // start
+ 'America/Los_Angeles', // timeZone
+) */
+
type DocRequestArgs = Parameters
export default async function handleRequest(...args: DocRequestArgs) {
diff --git a/app/routes/_pseo+/subject-data.ts b/app/routes/_marketing+/_pseo+/disciplinas.ts
similarity index 56%
rename from app/routes/_pseo+/subject-data.ts
rename to app/routes/_marketing+/_pseo+/disciplinas.ts
index 58401c0..47de3c1 100644
--- a/app/routes/_pseo+/subject-data.ts
+++ b/app/routes/_marketing+/_pseo+/disciplinas.ts
@@ -1,11 +1,7 @@
-import digitalSistemsFile from './files/sistemas-digitais.zip'
-import arquiteturaDeComputadores from './files/arquitetura-de-computadores.zip'
-import sistemasOperativos from './files/sistemas-operativos.zip'
+import digitalSistemsFile from './materia+/files/sistemas-digitais.zip'
+import arquiteturaDeComputadores from './materia+/files/arquitetura-de-computadores.zip'
+import sistemasOperativos from './materia+/files/sistemas-operativos.zip'
-type Resources = {
- name: string
- link: string
-}
type Software = {
name: string
link: string
@@ -19,10 +15,10 @@ type List = {
type Subject = {
slug: string
name: string
- prerequisites: string[]
- topics: List[]
- software: Software[]
- resources: Resources[]
+ prerequisites?: string[]
+ topics?: List[]
+ software?: Software[]
+ resources?: string
}
export const subjects: Subject[] = [
@@ -64,12 +60,7 @@ export const subjects: Subject[] = [
{ name: 'VHDL' },
{ name: 'ASICs' },
],
- resources: [
- {
- name: 'Matéria de Sistemas Digitais',
- link: digitalSistemsFile,
- },
- ],
+ resources: digitalSistemsFile,
software: [
{
name: 'Logisim',
@@ -116,12 +107,7 @@ export const subjects: Subject[] = [
{ name: 'Multiprocessadores' },
{ name: 'Paralelismo' },
],
- resources: [
- {
- name: 'Organização para Arquitetura de Computadores',
- link: arquiteturaDeComputadores,
- },
- ],
+ resources: arquiteturaDeComputadores,
software: [
{
name: 'MARS',
@@ -129,6 +115,10 @@ export const subjects: Subject[] = [
},
],
},
+ {
+ slug: 'assembly',
+ name: 'Assembly',
+ },
{
slug: 'sistemas-operativos',
name: 'Sistemas Operativos',
@@ -210,12 +200,7 @@ export const subjects: Subject[] = [
],
},
],
- resources: [
- {
- name: 'Organização para Sistemas Operativos',
- link: sistemasOperativos,
- },
- ],
+ resources: sistemasOperativos,
software: [
{
name: 'Linux',
@@ -235,4 +220,232 @@ export const subjects: Subject[] = [
},
],
},
+ {
+ slug: 'introducao-a-programacao',
+ name: 'Introdução à Programação',
+ },
+ {
+ slug: 'programacao',
+ name: 'Programação',
+ },
+ {
+ slug: 'programacao-orientada-a-objetos',
+ name: 'Programação Orientada a Objetos',
+ },
+ {
+ slug: 'programacao-funcional',
+ name: 'Programação Funcional',
+ },
+ {
+ slug: 'algoritmos',
+ name: 'Algoritmos',
+ },{
+ slug: 'c',
+ name: 'C',
+ },
+ {
+ slug: 'cpp',
+ name: 'C++',
+ },
+ {
+ slug: 'csharp',
+ name: 'C#',
+ },
+ {
+ slug: 'java',
+ name: 'Java',
+ },
+ {
+ slug: 'kotlin',
+ name: 'Kotlin',
+ },
+ {
+ slug: 'rust',
+ name: 'Rust',
+ },
+ {
+ slug: 'php',
+ name: 'PHP',
+ },
+ {
+ slug: 'html',
+ name: 'HTML',
+ },
+ {
+ slug: 'css',
+ name: 'CSS',
+ },
+ {
+ slug: 'javascript',
+ name: 'JavaScript',
+ },
+ {
+ slug: 'typescript',
+ name: 'TypeScript',
+ },
+ {
+ slug: 'python',
+ name: 'Python',
+ },
+ {
+ slug: 'spring-boot',
+ name: 'Spring Boot',
+ },
+ {
+ slug: 'react',
+ name: 'React',
+ },
+ {
+ slug: 'jpa',
+ name: 'JPA',
+ },
+ {
+ slug: 'python',
+ name: 'Python',
+ },
+ {
+ slug: 'estruturas-de-dados',
+ name: 'Estuturas de Dados',
+ },
+ {
+ slug: 'bases-de-dados',
+ name: 'Bases de Dados',
+ prerequisites: [
+ 'Aritmética',
+ 'Álgebra',
+ 'Sistemas numéricos',
+ 'Sistema binário',
+ 'Sistema octal',
+ 'Sistema hexadecimal',
+ 'Expressões lógicas',
+ 'Tipos de dados',
+ ],
+ topics: [
+ {
+ name: 'Introdução às Bases de Dados',
+ children: [
+ { name: 'Definição e função de uma base de dados' },
+ { name: 'Modelos de dados (relacional, hierárquico, em rede, orientado a objetos, etc.)' },
+ { name: 'Sistemas de gestão de bases de dados (SGBD)' },
+ { name: 'Normalização de bases de dados' },
+ ],
+ },
+ {
+ name: 'Modelo Relacional',
+ children: [
+ { name: 'Conceitos básicos de tabelas, tuplos, atributos, chaves, etc.' },
+ { name: 'Álgebra relacional' },
+ { name: 'Cálculo relacional' },
+ { name: 'Integridade referencial' },
+ { name: 'Normalização de bases de dados' },
+ ],
+ },
+ {
+ name: 'SQL',
+ children: [
+ { name: 'Linguagem de definição de dados (DDL)' },
+ { name: 'Linguagem de manipulação de dados (DML)' },
+ { name: 'Linguagem de controlo de dados (DCL)' },
+ { name: 'Linguagem de transações (DCL)' },
+ { name: 'Funções e procedimentos' },
+ ],
+ },
+ {
+ name: 'Modelo de Entidade-Relação (ER)',
+ children: [
+ { name: 'Conceitos básicos de entidades, relações, atributos, chaves, etc.' },
+ { name: 'Modelo de dados ER' },
+ { name: 'Modelo de dados extendido ER' },
+ { name: 'Normalização de bases de dados' },
+ ],
+ },
+ {
+ name: 'Bases de Dados Distribuídas',
+ children: [
+ { name: 'Conceitos básicos de bases de dados distribuídas' },
+ { name: 'Arquiteturas de bases de dados distribuídas' },
+ { name: 'Transações distribuídas' },
+ { name: 'Recuperação de falhas em bases de dados distribuídas' },
+ ],
+ },
+ {
+ name: 'Bases de Dados NoSQL',
+ children: [
+ { name: 'Conceitos básicos de bases de dados NoSQL' },
+ { name: 'Tipos de bases de dados NoSQL (documentais, chave-valor, colunares, etc.)' },
+ { name: 'Modelos de dados NoSQL' },
+ { name: 'Operações básicas em bases de dados NoSQL' },
+ ],
+ },
+ {
+ name: 'Bases de Dados Temporais',
+ children: [
+ { name: 'Conceitos básicos de bases de dados temporais' },
+ { name: 'Modelos de dados temporais' },
+ { name: 'Operações básicas em bases de dados temporais' },
+ { name: 'Recuperação de informação temporal' },
+ ],
+ },
+ {
+ name: 'Bases de Dados Espaciais',
+ children: [
+ { name: 'Conceitos básicos de bases de dados espaciais' },
+ { name: 'Modelos de dados espaciais' },
+ { name: 'Operações básicas em bases de dados espaciais' },
+ { name: 'Recuperação de informação espacial' },
+ ],
+ },
+ ],
+ resources: sistemasOperativos,
+ software: [
+ {
+ name: 'SQLite',
+ link: 'https://sqlite.org/',
+ },
+ {
+ name: 'MySQL',
+ link: 'https://www.mysql.com/',
+ },
+ {
+ name: 'PostgreSQL',
+ link: 'https://www.postgresql.org/',
+ },
+ {
+ name: 'MongoDB',
+ link: 'https://www.mongodb.com/',
+ },
+ {
+ name: 'Cassandra',
+ link: 'http://cassandra.apache.org/',
+ },
+ ],
+ },
+ {
+ slug: 'sql',
+ name: 'SQL',
+ },
+ {
+ slug: 'redes-de-computadores',
+ name: 'Redes de Computadores',
+ },
+ {
+ slug: 'algebra-linear',
+ name: 'Álgebra Linear',
+ },
+ {
+ slug: 'calculo',
+ name: 'Cálculo',
+ },
+ {
+ slug: 'excel',
+ name: 'Excel',
+ },
+ {
+ slug: 'microsoft-office',
+ name: 'Microsoft Office',
+ },
+ {
+ slug: 'word',
+ name: 'Word',
+ },
]
diff --git a/app/routes/_pseo+/explicacoes.$subjectslug.tsx b/app/routes/_marketing+/_pseo+/explicacoes+/$subjectslug.tsx
similarity index 92%
rename from app/routes/_pseo+/explicacoes.$subjectslug.tsx
rename to app/routes/_marketing+/_pseo+/explicacoes+/$subjectslug.tsx
index c7aa4ae..351c277 100644
--- a/app/routes/_pseo+/explicacoes.$subjectslug.tsx
+++ b/app/routes/_marketing+/_pseo+/explicacoes+/$subjectslug.tsx
@@ -23,7 +23,7 @@ import satisfactionGuarantee from '~/routes/_marketing+/images/satisfaction-guar
import signatureBlack from '~/routes/_marketing+/images/signature-black.png'
import signatureWhite from '~/routes/_marketing+/images/signature-white.png'
import { Link, useLoaderData } from '@remix-run/react'
-import { type LoaderArgs, json, type LinksFunction, type V2_MetaFunction } from '@remix-run/node'
+import { type LoaderArgs, json, type LinksFunction, type V2_MetaFunction, type ActionArgs } from '@remix-run/node'
import { Container } from '~/ui_components/layout/container.tsx'
import { H1 } from '~/ui_components/typography/h1.tsx'
import { P } from '~/ui_components/typography/p.tsx'
@@ -31,10 +31,20 @@ import { H2 } from '~/ui_components/typography/h2.tsx'
import { H3 } from '~/ui_components/typography/h3.tsx'
import { Span } from '~/ui_components/typography/span.tsx'
import { H4 } from '~/ui_components/typography/h4.tsx'
-import BackgroundDiagonal from '../_marketing+/components/bg-diagonal.tsx'
-import BackgroundBlur from '../_marketing+/components/bg-blur.tsx'
-import BackgroundSquareLines from '../_marketing+/components/bg-square-lines.tsx'
-import { subjects } from './subject-data.ts'
+import BackgroundDiagonal from '../../components/bg-diagonal.tsx'
+import BackgroundBlur from '../../components/bg-blur.tsx'
+import BackgroundSquareLines from '../../components/bg-square-lines.tsx'
+import { subjects } from '../disciplinas.ts'
+import { validateCSRF } from '~/utils/csrf.server.ts'
+import { checkHoneypot } from '~/utils/honeypot.server.ts'
+import { parse } from '@conform-to/zod'
+import { emailSchema } from '~/utils/user-validation.ts'
+import { z } from 'zod'
+import { prisma } from '~/utils/db.server.ts'
+import { sendEmail } from '~/utils/email.server.ts'
+import { ResourcesEmail } from '../materia+/tutoring.emails.tsx'
+import { getDomainUrl } from '~/utils/misc.ts'
+import { generateTOTP } from '~/utils/totp.server.ts'
export const meta: V2_MetaFunction = ({ params }) => {
const { subjectslug } = params
@@ -110,7 +120,7 @@ export async function loader({ params }: LoaderArgs) {
const Route = () => {
const { subject } = useLoaderData()
- const { name, prerequisites, topics, resources, software } = subject
+ const { name } = subject
const features = [
{
name: 'Aulas online por video-conferência',
@@ -407,7 +417,7 @@ const Route = () => {
return classes.filter(Boolean).join(' ')
}
- const navigation = {
+ const subjectsITeach = {
programming: [
{ name: 'C, C++, C#, Java, PHP, Python' },
{ name: 'Kotlin (Android)' },
@@ -549,7 +559,7 @@ const Route = () => {
Passei!
- Como é que isto é possível? Porque tiveste aulas de programação comigo! Eu ensinei como estudar {name} e aprendeste um método cientificamente
+ Como é que isto é possível? Porque tiveste aulas de {name} comigo! Eu ensinei como estudar {name} e aprendeste um método cientificamente
provado para memorizar tudo o que for importante. Para além disso, vou ao encontro do teu nível de conhecimento atual e ajudo-te a fazer a ponte entre o
conhecimento que tens agora e o conhecimento que precisarás para passar no exames. Podes ter explicações dedicadas só a ti ou em grupo.
@@ -597,86 +607,6 @@ const Route = () => {
-
-
-
-
-
- {name}
-
-
- Estas são as matérias que precisas de saber para tirares o máximo proveito das explicações de {name}.
-
Só quero agradecer-te por reservares um tempo para leres sobre meu serviço de tutoria. Continua a ser uma tremenda honra ter tantos alunos que confiam em mim para
- ajudá-los a encontrar uma maneira melhor de frequentar a faculdade. Sinceramente espero que tenhas decidido ter tutoria de programação, mesmo que não comigo,
+ ajudá-los a encontrar uma maneira melhor de frequentar a faculdade. Sinceramente espero que tenhas decidido ter tutoria de {name}, mesmo que não comigo,
porque sei que é uma decisão muito boa.
@@ -1135,3 +1065,97 @@ const Route = () => {
)
}
export default Route
+
+const newsletterSchema = z.object({ email: emailSchema })
+export const verificationType = `resources`
+
+export async function action({ request, params }: ActionArgs) {
+ const { subjectslug } = params
+ const subject = subjects.find(s => s.slug === subjectslug)!
+ const { name } = subject
+ const formData = await request.formData()
+
+ // Check for bots
+ await validateCSRF(formData, request.headers)
+ checkHoneypot(formData, '/newsletter')
+
+ // Parse form
+ const submission = parse(formData, { schema: newsletterSchema })
+ if (submission.intent !== 'submit') {
+ return json({ status: 'error', submission } as const)
+ }
+ if (!submission.value) {
+ return json({ status: 'error', submission } as const, { status: 400 })
+ }
+
+ // Extract data
+ const { email } = submission.value
+
+ const resourcesURL = new URL(`${getDomainUrl(request)}/explicacoes/${subjectslug}/recursos`)
+ resourcesURL.searchParams.set('email', email)
+
+ const oneDay = 60 * 60 * 24 // One day in seconds
+ const target = email
+ const { otp, secret, algorithm, period, digits } = generateTOTP({ algorithm: 'sha256', period: oneDay })
+ // delete old verifications. Users should not have more than one verification
+ // of a specific type for a specific target at a time.
+ await prisma.verification.deleteMany({
+ where: { type: verificationType, target },
+ })
+ await prisma.verification.create({
+ data: {
+ type: verificationType,
+ target,
+ algorithm,
+ secret,
+ period,
+ digits,
+ expiresAt: new Date(Date.now() + period * 1000),
+ },
+ })
+
+ // add the otp to the url we'll email the user.
+ resourcesURL.searchParams.set('code', otp)
+
+ // Schedule emails
+ await scheduleEmailSequence(email)
+
+ // Send email with resource link
+ await sendEmail({
+ to: email,
+ subject: `🚀 Recursos para estudantes de ${name}`,
+ react: ,
+ })
+
+ // Everything ok
+ return json({ status: 'success', submission } as const)
+}
+
+async function scheduleEmailSequence(email: string) {
+ const now = new Date()
+ const in1Day = new Date(now.getTime() + 1 * 24 * 3600 * 1000)
+ const in2Days = new Date(now.getTime() + 2 * 24 * 3600 * 1000)
+ const in3Days = new Date(now.getTime() + 3 * 24 * 3600 * 1000)
+ const in4Days = new Date(now.getTime() + 4 * 24 * 3600 * 1000)
+ const scheduleDates = [in1Day, in2Days, in3Days, in4Days]
+ for (let i = 0; i < scheduleDates.length; i++) {
+ const scheduledAt = scheduleDates[i]
+ const sequence = i + 1
+ await prisma.emailSchedule.upsert({
+ where: {
+ to_sequence: {
+ to: email,
+ sequence,
+ },
+ },
+ update: {
+ scheduledAt: scheduledAt,
+ },
+ create: {
+ to: email,
+ sequence,
+ scheduledAt: scheduledAt,
+ },
+ })
+ }
+}
diff --git a/app/routes/_marketing+/_pseo+/materia+/$subjectslug.tsx b/app/routes/_marketing+/_pseo+/materia+/$subjectslug.tsx
new file mode 100644
index 0000000..910631c
--- /dev/null
+++ b/app/routes/_marketing+/_pseo+/materia+/$subjectslug.tsx
@@ -0,0 +1,1324 @@
+import { Button } from '~/components/ui/button.tsx'
+import { Icon } from '~/components/ui/icon.tsx'
+import collegeLife from '~/routes/_marketing+/images/college-life.jpg'
+import andreOnMacBookPro from '~/routes/_marketing+/images/andre-on-macbook-pro.png'
+import goncaloBarreiros from '~/routes/_marketing+/images/goncalo-barreiros.png'
+import pauloJorge from '~/routes/_marketing+/images/paulo-jorge.png'
+import luciaZiyuan from '~/routes/_marketing+/images/lucia-ziyuan.png'
+import catiaSilva from '~/routes/_marketing+/images/catia-silva.png'
+import marcoBarreiros from '~/routes/_marketing+/images/marco-barreiros.png'
+import dejanMilosevic from '~/routes/_marketing+/images/dejan-milosevic.png'
+import yev from '~/routes/_marketing+/images/yev.png'
+import alexandreMiguelPinto from '~/routes/_marketing+/images/alexandre-miguel-pinto.png'
+import lilianaFerreira from '~/routes/_marketing+/images/liliana-ferreira.png'
+import paulaAlexandraSilva from '~/routes/_marketing+/images/paula-alexandra-silva.png'
+import joseGuimaraes from '~/routes/_marketing+/images/jose-guimaraes.png'
+import kirillLapshev from '~/routes/_marketing+/images/kirill-lapshev.png'
+import fabianaMilanez from '~/routes/_marketing+/images/fabiana-milanez.png'
+import apoZadeh from '~/routes/_marketing+/images/apo-zadeh.png'
+import inesBarreiros from '~/routes/_marketing+/images/ines-barreiros.png'
+import leahMeirinhos from '~/routes/_marketing+/images/leah-meirinhos.png'
+import miguelFerreira from '~/routes/_marketing+/images/miguel-ferreira.png'
+import satisfactionGuarantee from '~/routes/_marketing+/images/satisfaction-guarantee.png'
+import signatureBlack from '~/routes/_marketing+/images/signature-black.png'
+import signatureWhite from '~/routes/_marketing+/images/signature-white.png'
+import * as newsletterAnimation from '~/components/newsletter-animation.json'
+import { Form, Link, useActionData, useLoaderData, useNavigation } from '@remix-run/react'
+import { type LoaderArgs, json, type LinksFunction, type V2_MetaFunction, type ActionArgs } from '@remix-run/node'
+import { Container } from '~/ui_components/layout/container.tsx'
+import { H1 } from '~/ui_components/typography/h1.tsx'
+import { P } from '~/ui_components/typography/p.tsx'
+import { H2 } from '~/ui_components/typography/h2.tsx'
+import { H3 } from '~/ui_components/typography/h3.tsx'
+import { Span } from '~/ui_components/typography/span.tsx'
+import { H4 } from '~/ui_components/typography/h4.tsx'
+import BackgroundDiagonal from '../../components/bg-diagonal.tsx'
+import BackgroundBlur from '../../components/bg-blur.tsx'
+import BackgroundSquareLines from '../../components/bg-square-lines.tsx'
+import { subjects } from '../disciplinas.ts'
+import { validateCSRF } from '~/utils/csrf.server.ts'
+import { checkHoneypot } from '~/utils/honeypot.server.ts'
+import { parse } from '@conform-to/zod'
+import { emailSchema } from '~/utils/user-validation.ts'
+import { z } from 'zod'
+import { useForm } from '@conform-to/react'
+import { useEffect, useRef, useState } from 'react'
+import { Player } from '@lottiefiles/react-lottie-player'
+import { AuthenticityTokenInput } from 'remix-utils/csrf/react'
+import { HoneypotInputs } from 'remix-utils/honeypot/react'
+import { Flex } from '~/ui_components/layout/flex.tsx'
+import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
+import { Label } from '~/components/ui/label.tsx'
+import { Input } from '~/components/ui/input.tsx'
+import { prisma } from '~/utils/db.server.ts'
+import { sendEmail } from '~/utils/email.server.ts'
+import { ResourcesEmail } from '../materia+/tutoring.emails.tsx'
+import { getDomainUrl } from '~/utils/misc.ts'
+import { generateTOTP } from '~/utils/totp.server.ts'
+
+export const meta: V2_MetaFunction = ({ params }) => {
+ const { subjectslug } = params
+ const subject = subjects.find(s => s.slug === subjectslug)!
+ const { name } = subject
+ return [
+ { title: `Explicações de ${name}` },
+ {
+ name: 'description',
+ content: `Procuras explicações de ${name} e queres resultados? Ajudei 650+ alunos a obliterar os exames! Satisfação 100% garantida!`,
+ },
+ {
+ name: 'keywords',
+ content: `explicações de ${name}, explicador de ${name}, tutoria de ${name}, tutor de ${name}, professor particular de ${name}, boas notas ${name}, como estudar ${name}`,
+ },
+ ]
+}
+
+export const links: LinksFunction = () => {
+ return [
+ {
+ rel: 'preload',
+ href: collegeLife,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: andreOnMacBookPro,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: goncaloBarreiros,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: pauloJorge,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: miguelFerreira,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: satisfactionGuarantee,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: signatureBlack,
+ as: 'image',
+ },
+ {
+ rel: 'preload',
+ href: signatureWhite,
+ as: 'image',
+ },
+ /* {
+ rel: 'canonical',
+ href: 'https://andrecasal.com/explicacoes-de-programacao',
+ }, */
+ ]
+}
+
+export async function loader({ params }: LoaderArgs) {
+ const { subjectslug } = params
+ const subject = subjects.find(s => s.slug === subjectslug)!
+ return json({ subject })
+}
+
+const Route = () => {
+ const { subject } = useLoaderData()
+ const { name, prerequisites, topics, software } = subject
+ const features = [
+ {
+ name: 'Aulas online por video-conferência',
+ description: 'Explicações com áudio, vídeo, whiteboard e controlo remoto para te ajudar a organizar a matéria, programar, e explicar conceitos da melhor forma possível.',
+ icon: 'video',
+ },
+ {
+ name: 'Gravações privadas gratuitas',
+ description: 'Acesso vitalício a uma playlist privada com todas as nossas sessões, para puderes rever a matéria sempre que precisares.',
+ icon: 'play',
+ },
+ {
+ name: 'Acesso ilimitado a mim',
+ description: 'Falar comigo está a um clique de distância por WhatsApp. Estás bloqueado? Envia-me uma mensagem e eu respondo-te.',
+ icon: 'chat',
+ },
+ {
+ name: 'Compromisso ético',
+ description: 'Eu comprometo-me a não fazer batota. Ajudo-te a entender a matéria e a tirar dúvidas, mas não farei o teu trabalho por ti.',
+ icon: 'heart',
+ },
+ ]
+
+ const featuredTestimonial = {
+ body: 'Antes de começar a ser orientado pelo André, eu odiava Assembly e Microprocessadores. Eu estava a repetir a disciplina pela terceira vez e senti que ia reprovar mais uma vez. Mas depois que comecei a ser orientado pelo André, comecei a gostar do que estava a aprender, porque comecei a entender a matéria e até ficou divertido! Pela primeira vez, senti-me confiante! O André é muito simpático e paciente: ele desenhava diagramas, explicava, e usava outras linguagens de programação para me ajudar a ver a ligação entre linguagens de alto nível e Assembly, e tudo estava ótimo! Nunca tive um professor assim. Quando o resultado do exame chegou, fiquei perplexo ao ver que havia ido de reprovado nessa matéria por dois anos consecutivos para ter um 16! O método de ensino e a dedicação do André são, na minha opinião, imbatíveis.',
+ author: {
+ name: 'Gonçalo Barreiros',
+ imageUrl: goncaloBarreiros,
+ },
+ }
+
+ const testimonials = [
+ [
+ [
+ {
+ body: 'Os meus professores introduziram a programação do Arduino com pequenos blocos de código. Um pouco de código aqui e ali. Mas eles nunca explicaram as coisas muito bem. Eles presumiam que íamos procurar as peças que faltavam. Tentei pesquisar na internet e conversar com colegas, mas não consegui encontrar bons recursos na internet e meus amigos estavam tão perdidos quanto eu. Quando comecei as aulas de reforço com o André, minhas notas aumentaram exponencialmente. Estou com o André há um ano neste momento, a disciplina atual é a segunda que estamos a fazer juntos. Na primeira aula, se eu sei alguma coisa sobre Arduino, foi porque o André me ensinou. Quero dizer, o André não apenas me ensinou como a fazer projetos com Arduino, mas também me ensinou ao ponto de eu poder concluir os exames sozinho! E em termos de disponibilidade o André é top.',
+ author: {
+ name: 'Paulo Jorge',
+ imageUrl: pauloJorge,
+ },
+ },
+ {
+ body: 'O André é um professor muito amável que coloca o progresso dos seus alunos no centro da sua prática de ensino. Ele preocupa-se pessoalmente e adapta o seu ensino aos interesses e necessidades individuais dos alunos. Ele traz muitos anos de experiência do mundo real na construção de aplicações e negócios de sucesso para o seu ensino. Para além de ser um professor de programação muito conhecedor, também é apaixonado pela aprendizagem - crescimento pessoal, filosofia, saúde e afins. Aprenderá muito com ele para além da programação em si.',
+ author: {
+ name: 'Lucia Ziyuan',
+ imageUrl: luciaZiyuan,
+ },
+ },
+ {
+ body: 'Eu não conseguia entender a matéria da aula que estava a ser dada pelos professores. Eles não estavam a fazer um bom trabalho e não nos davam os recursos necessários. Tentei ir à biblioteca da universidade, tentei conversar com colegas que entendiam um pouco mais da aula mas não adiantou muito. A diferença [entre ter e não ter explicações com o André] é que eu não passaria nas provas. Tenho obtido resultados. Tem sido uma boa experiência, tenho aprendido e melhorado.',
+ author: {
+ name: 'Miguel Ferreira',
+ imageUrl: miguelFerreira,
+ },
+ },
+ {
+ body: 'É maravilhoso trabalhar com André! Ele é experiente e compassivo, e tem ideias inovadoras, paixão e amor por seu trabalho. Altamente recomendado!',
+ author: {
+ name: 'Amalia Sirica',
+ },
+ },
+ {
+ body: 'Já conheço o André há algum tempo. Ele é um ótimo programador e se mantém atualizado com as melhores práticas do setor. Altamente recomendado',
+ author: {
+ name: 'Zuki G',
+ },
+ },
+ {
+ body: 'Ajudou muito, foi muito paciente e interessado em ensinar e explicar o assunto.',
+ author: {
+ name: 'Isabel Bozzato',
+ },
+ },
+ {
+ body: 'Excelente explicador!',
+ author: {
+ name: 'José Maria',
+ },
+ },
+ { author: { name: 'Lecticia Benchimol' } },
+ { author: { name: 'Marisa Oliveira' } },
+ ],
+ [
+ {
+ body: 'André é um tutor e mentor de programação absolutamente estelar. Sempre disponível para fornecer feedback pessoal, conselhos e orientação.',
+ author: {
+ name: 'Paula Alexandra Silva',
+ imageUrl: paulaAlexandraSilva,
+ },
+ },
+ {
+ body: 'André é um excelente tutor, todos os conceitos ficam realmente compreensíveis com suas explicações. Altamente recomendado! 💪',
+ author: {
+ name: 'Alexandre Miguel Pinto',
+ imageUrl: alexandreMiguelPinto,
+ },
+ },
+ {
+ body: 'O André é excelente mesmo!',
+ author: {
+ name: 'Inês V. Barreiros',
+ imageUrl: inesBarreiros,
+ },
+ },
+ {
+ body: 'Incrível!!!!',
+ author: {
+ name: 'Léa Meirinhos',
+ imageUrl: leahMeirinhos,
+ },
+ },
+ {
+ body: 'O professor André explica muito bem e tem imensa paciência. Eu estou extremamente grata!!',
+ author: {
+ name: 'Daniela Alexandra',
+ },
+ },
+ {
+ body: 'O André é um profissional que domina o que faz. Nota-se a sua paixão e entrega, mas sobretudo valorizo a sua disponibilidade em validar e perceber as necessidades do meu projeto; sempre com uma visão construtiva e com soluções interessantes que se tornaram numa mais-valia e algo diferenciador no mercado.',
+ author: {
+ name: 'Ana Mendes',
+ },
+ },
+ {
+ body: 'Olá André! Espero que esteja tudo bem! Enquanto isso, as notas foram publicadas [...] A de programação foi muito melhor do que eu esperava! [Captura de tela com nota de 17] A programação acabou por ser a melhor ahah!',
+ author: {
+ name: 'Guilherme Echeverri',
+ },
+ },
+ {
+ body: 'É excelente ter explicações com o André. Entendo tudo!',
+ author: {
+ name: 'Maria Isabel',
+ },
+ },
+ {
+ body: 'Ótimo explicador. Muito dedicado e paciente.',
+ author: {
+ name: 'Musslima Ibraimo',
+ },
+ },
+ {
+ body: 'Muito bom!',
+ author: {
+ name: 'Wilson Mesquita',
+ },
+ },
+ { author: { name: 'Kátia Santos' } },
+ { author: { name: 'Gleice Santos' } },
+ ],
+ ],
+ [
+ [
+ {
+ body: 'André sempre foi muito profissional, motivado e apaixonado pelo que faz. E quando está a ensinar, é a pessoa mais dedicada que conheço. Ele traz à tona o melhor que há nas pessoas, em qualquer circunstância. Sempre com um sorriso e uma atitude positiva, é entusiasmante trabalhar com ele!',
+ author: {
+ name: 'Dejan Milosevic',
+ imageUrl: dejanMilosevic,
+ },
+ },
+ {
+ body: 'Tried many courses online with no tangible progress, glad I found Andre, where one size fits all mentality is avoided.',
+ author: {
+ name: 'Apo Zadeh',
+ imageUrl: apoZadeh,
+ },
+ },
+ {
+ body: 'Um dos professores e mentores mais incríveis que conheci! Gentil e gentil, ele é um ótimo ouvinte e uma das pessoas mais calorosas que conheço. É um prazer enorme ser seu aluno 🫶',
+ author: {
+ name: 'Yev',
+ imageUrl: yev,
+ },
+ },
+ {
+ body: 'Fiquei com a impressão de que 2h era pouco tempo, e que o Prof. André poderia ter-nos ajudado mais, não fossem os exercícios da minha faculdade serem supostamente pouco convencionais.',
+ author: {
+ name: 'Henrique Silvestre',
+ },
+ },
+ {
+ body: 'É perfeito. Recomendo 100%. Não poderia ter encontrado melhor. Muito grato por tudo.',
+ author: {
+ name: 'Isabel Rodrigues',
+ },
+ },
+ {
+ body: 'Profissional: competência e disponibilidade.',
+ author: {
+ name: 'Jaime Torrinhas',
+ },
+ },
+ {
+ body: 'Um excelente explicador! Sabe como orientar passo-a-passo para resolver problemas. Experiência muito boa em geral.',
+ author: {
+ name: 'Miguel Lomba',
+ },
+ },
+ { author: { name: 'João Pedro Araújo' } },
+ { author: { name: 'Inês Gouveia' } },
+ { author: { name: 'Lúcia Rocha' } },
+ { author: { name: 'João Telmo' } },
+ { author: { name: 'João Pimentel' } },
+ ],
+ [
+ {
+ body: 'O André é um profissional inteligente super acessível e tem o dom de conseguir tornar simples o que à maioria parece complexo. :) Super Recomendo',
+ author: {
+ name: 'Liliana Ferreira',
+ imageUrl: lilianaFerreira,
+ },
+ },
+ {
+ body: 'O André é um professor dedicado e muito comprometido. Tem uma capacidade de leitura e compreensão das necessidades que superou sempre as minhas expectativas. Tem interesse em ajudar sempre mais! É um conhecedor, gosta de aprender e ler sobre tudo, por isso quem o procurar vai ter explicações nao só de programação mas de outras áreas que se cruzem ou sejam necessárias. Recomendo muito, garantidamente é um contacto enriquecedor!',
+ author: {
+ name: 'Cátia Silva',
+ imageUrl: catiaSilva,
+ },
+ },
+ {
+ body: 'O André é um excelente professor! Sua paciência e clareza ao explicar os conceitos são notáveis. Sinto-me muito grato por suas aulas extras e definitivamente voltarei a procurá-lo se precisar de ajuda novamente. Recomendo totalmente!!!! Muito obrigado, André!',
+ author: {
+ name: 'Marco Barreiros',
+ imageUrl: marcoBarreiros,
+ },
+ },
+ {
+ body: 'Excelente profissional! Deu-me uma grande ajuda a perceber melhor programação!',
+ author: {
+ name: 'Kirill Lapshev',
+ imageUrl: kirillLapshev,
+ },
+ },
+ {
+ body: 'André tem muita paciência, comunicação clara e didática.',
+ author: {
+ name: 'Fabiana Milanez',
+ imageUrl: fabianaMilanez,
+ },
+ },
+ {
+ body: 'O professor André Casal é um excelente explicador, muito dedicado e atento as necessidades dos alunos. Recomendo vivamente!',
+ author: {
+ name: 'José Guimarães',
+ imageUrl: joseGuimaraes,
+ },
+ },
+ {
+ body: 'Muito bom professor. Ajudou-me imenso em introdução à programação em Java. Recomendo a todos os que não entendam bem as aulas na faculdade pois o professor André dá explicações bastante detalhadas e esclarecedoras até entenderem tudo.',
+ author: {
+ name: 'Alfredo Soudo',
+ },
+ },
+ {
+ body: 'André Casal é o explicador mais inteligente, trabalhador e atencioso que conheço. Se deseja receber ajuda do mais alto nível, trabalhe com ele!',
+ author: {
+ name: 'Mony Chhim',
+ },
+ },
+ {
+ body: 'Estou muito grata por toda a ajuda: conhecimento, disponibilidade, paciência e, acima de tudo, pela gentileza. Obrigado!',
+ author: {
+ name: 'Maria Ribeiro',
+ },
+ },
+ {
+ body: 'O André foi muito paciente comigo e explicou tudo muito bem. Se eu precisar de ajuda novamente... é com ele.',
+ author: {
+ name: 'Marcos Marcos',
+ },
+ },
+ {
+ body: 'Além das expectativas!',
+ author: {
+ name: 'Helena Oliveira',
+ },
+ },
+ { author: { name: 'Csongor Csaba Horvath' } },
+ { author: { name: 'Ricardo Escudeiro' } },
+ { author: { name: 'Peter Delle' } },
+ { author: { name: 'Arthur Constantino' } },
+ ],
+ ],
+ ]
+
+ const stats = [
+ { name: 'Número de estudantes', value: '650+' },
+ { name: 'Matérias ensinadas', value: '51+' },
+ { name: 'Nota média', value: '16.4' },
+ { name: 'Taxa de sucesso', value: '99.5%' },
+ ]
+
+ function classNames(...classes: string[]) {
+ return classes.filter(Boolean).join(' ')
+ }
+
+ const subjectsITeach = {
+ programming: [
+ { name: 'C, C++, C#, Java, PHP, Python' },
+ { name: 'Kotlin (Android)' },
+ { name: 'Swift (iOS)' },
+ { name: 'Clean Code' },
+ { name: 'Programação Funcional' },
+ { name: 'Programação Orientada a Objetos' },
+ { name: 'Programação Imperativa e Declarativa' },
+ { name: 'Test-Driven Development (TDD)' },
+ ],
+ webdev: [
+ { name: 'HTML, CSS, JS' },
+ { name: 'O protocolo HTTP' },
+ { name: 'React, Vue, Angular' },
+ { name: 'Styled Components' },
+ { name: 'TailwindCSS' },
+ { name: 'Browser, Node, Deno APIs' },
+ { name: 'Express, Next, Remix' },
+ { name: 'REST and GraphQL APIs' },
+ { name: 'Git & GitHub' },
+ { name: 'Databases (SQL, SQLite, Mongo)' },
+ ],
+ computerscience: [
+ { name: 'Sistemas Digitais' },
+ { name: 'Organização e Arquitetura de Computadores' },
+ { name: 'Assembly (x86, x86-64, ARM, MIPS)' },
+ { name: 'Sistemas Operativos' },
+ { name: 'Redes de Computadores' },
+ { name: 'Estruturas de dados' },
+ { name: 'Algoritmos' },
+ ],
+ math: [{ name: 'Álgebra' }, { name: 'Analise matemática' }, { name: 'Cálculo' }, { name: 'Análise numérica' }],
+ }
+
+ const includedFeatures = ['Estudar a par', 'Esclarecer dúvidas', 'Resolver desafios difíceis', 'Ajuda com projetos']
+
+ const singleSessionFeatures = ['Estudar a par', 'Esclarecer dúvidas', 'Resolver desafios difíceis', 'Ajuda com projetos']
+
+ const actionData = useActionData()
+ const navigation = useNavigation()
+ const [form, { email }] = useForm({
+ lastSubmission: actionData?.submission,
+ shouldValidate: 'onBlur',
+ onValidate: ({ formData }) => parse(formData, { schema: newsletterSchema }),
+ })
+ const playerRef = useRef(null)
+ const [state, setState] = useState<'initial' | 'animating' | 'finished'>('initial')
+
+ useEffect(() => {
+ if (actionData?.status === 'success') {
+ setState('animating')
+ playerRef.current?.play()
+ }
+ }, [actionData])
+
+ return (
+ <>
+
+
+
+
+
+ Matéria de {name}
+
+
+ Queres resultados a {name}? Ajudei 650+ alunos a obliterar os exames! Satisfação 100% garantida!
+
+
+
+ Quero ter excelentes notas!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {name}
+
+
+ Estas são as matérias que precisas de saber para tirares o máximo proveito das explicações de {name}.
+
+
+
+
+
+
+
+
Pré-requisitos
+
+ {prerequisites.map(name => (
+
+ {name}
+
+ ))}
+
+
+
+
Tópicos
+
+ {topics.map(({ name, children }) => (
+
+ {name}
+ {children ? (
+
+ {children.map(({ name }) => (
+
+ {name}
+
+ ))}
+
+ ) : null}
+
+ ))}
+
+
+
+
Software
+
+ {software.map(({ name, link }) => (
+
+
+
+ {name}
+
+
+
+ ))}
+
+
+
+
+
+
Recursos gratuitos
+
+ Queres receber recursos gratuitos para te ajudar a estudar? Insere o teu email e receberás no teu email imagens, videos, documentos e textos que te ajudarão a
+ estudar.
+
+ Receberás no teu email um link especial para acederes aos recursos gratuitos!
+
+
+
+
+
+
+
+
+
+
+ A vida universitária
+
+
+ Ok, estás na universidade e não queres ser desrespeitado, envergonhado e humilhado pelos teus colegas. Muito menos pelos professores. Tendo passado pela universidade
+ e sendo explicador e mentor há mais de {new Date().getFullYear() - 2006} anos, sei como é. Sentes que os professores não se preocupam suficientemente contigo, os teus
+ colegas estão tão perdidos como tu, e ir à biblioteca não vai fazer as tuas notas magicamente subir. Para além disso, passar mais tempo a ler os livros da
+ bibliografia das disciplinas não te vai ajudar porque não podes perder ainda mais tempo, e já dormes menos do que seria saudável.
+
+
+
+ Até já podes ter experimentado centros de explicações. Lembro-me de ir a um centro de explicações para Cálculo quando estava no secundário. Arranjei a minha
+ mochila, saí de casa e 1h mais tarde cheguei ao centro e estava a estudar. Estávamos a pagar 30€/hora por uma professora numa sala cheia de alunos. Durante as
+ duas horas que lá estive consegui colocar exatamente duas perguntas à professora, cujas respostas foram curtas e apressadas demais para eu perceber alguma coisa.
+ A Professora queria distribuir o seu tempo por todos os alunos aparentemente. Lembro-me de me perguntar será que vale a pena perder 2 horas para ir e vir e pagar
+ 30€/hora para vir para aqui fazer exercícios e apenas obter a atenção da Professora duas vezes em 2 horas? Para isto estudo em casa!
+
+
+ Depois disso experimentei um tutor privado de matemática. Ele sabia a matéria, mas não conseguia fazer a ponte entre o meu conhecimento e o conhecimento dele. Ele
+ não conseguia perceber que conhecimento de fundo me faltava para compreender os conceitos atuais, então mecanisticamente repetia as mesmas respostas que eu não
+ seria capaz de perceber enquanto ele não me fornecesse o conhecimento de fundo necessário. Foi frustrante.
+
+
+ Estás à procura de uma solução melhor de subires as tuas notas e sentires-te orgulhoso de ti próprio e daquilo que conseguirás atingir? É por isso que estou aqui.
+ Para te ajudar a dominar a matéria da universidade e a ganhares notas excelentes com tutoria dedicada a ti!
+
+
+ De iniciante a perito
+
+
+ Imagina-te a comandar o respeito e admiração dos teus pais, professores e colegas. Uau filho (ou filha), estás-te mesmo a safar bem na universidade! Imagina os
+ professores: malta, se tiveres dúvidas perguntem-lhe a ele (ou ela) que sabe muito disto! Imagina os teus colegas a identificarem o teu conhecimento e a
+ pedirem-te para guiares sessões de estudo com eles!
+
+
+
+
+ Como é trabalhar com um explicador de {name}
+
+
+
+ Imagina isto: o teu professor fazer-te uma pergunta que sabe que nenhum estudante sabe responder. Mas tu tens uma arma secreta - lições com um tutor especializado
+ em ciência da computação e com skills de comunicação excelentes e que tas ensina. Ao começares a brilhantemente responder à pergunta do professor, os teus colegas
+ começam a olhar para ti com admiração e forma-se na face do teu professor um sorriso de aprovação. Quando acabas de dar a tua resposta, faz-se silêncio enquanto o
+ choque da tua resposta subside. Sentes um surto de adrenalina quando de apercebes que toda a gente está a olhar para ti. Sorris e o teu professor diz: Malta, eu
+ se fosse a vocês fazia amizade com ele, ele vai longe!
+
+
+ Durante o resto da aula todos os teus colegas vão estar a pensar que tu serás um bom amigo para ter. Confia em mim, não vais ter problemas a fazer amigos na
+ universidade. O teu maior problema vai ser distinguir entre as pessoas que gostam de ti por valorizarem inteligência e as pessoas que se querem aproveitar de ti
+ para lhes explicares a matéria.
+
+
+ Estás a fazer os exames. Confiante. Concentrado. Os teus colegas lutam para se lembrarem dos conceitos para responderem às questões. Tu passas a parte de
+ memorização do exame com uma perna às costas. Um excelente começo faz-te sentir ainda mais confiante e dá-te bastante mais tempo para responder às questões que
+ realmente requerem trabalho. Ainda faltam 20 minutos para o exame acabar mas já acabaste. Com calma e confiança revês o exame e ainda corriges um pequeno erro -
+ mais meio ponto na classificação. Faltam 10 minutos. Entregas o exame cedo, sentido-te orgulhoso de ti próprio e do que atingiste! Sais da sala, pegas no
+ telemóvel e ligas aos teus pais.
+
+
+
Estou filho?
+
Passei!
+
+
+ Como é que isto é possível? Porque tiveste aulas de programação comigo! Eu ensinei como estudar {name} e aprendeste um método cientificamente
+ provado para memorizar tudo o que for importante. Para além disso, vou ao encontro do teu nível de conhecimento atual e ajudo-te a fazer a ponte entre o
+ conhecimento que tens agora e o conhecimento que precisarás para passar no exames. Podes ter explicações dedicadas só a ti ou em grupo.
+
+
+
+
Eu dedico-me aos meus alunos
+
+ Estás a estudar na biblioteca com os teus colegas e encontras um problema que não sabes resolver. Perguntas aos teus colegas mas ninguém sabe a resposta. Estás
+ bloqueado. Abres o browser e pesquisas no google. Sabes que é uma solução rápida, mas não encontras a resposta online. Mas lembras-te que tens um tutor de
+ confiança sempre ao teu lado! Pegas no telefone, abres o Whatsapp e escreves uma pequena mensagem. Um minuto depois recebes uma explicação clara que responde
+ exatamente à dúvida que tinhas. Sentes-te aliviado e agradecido por conseguires continuar a estudar sem solavancos no caminho.
+
+
+ A taxa média de positivas dos meus mais de 650 alunos é de 98,75%. Eu dedico-me aos meus alunos e não descanso enquanto eles não têm resposta a todas as suas
+ questões! Eu dou-te suporte por Whatsapp para que tenhas a liberdade de colocar todas as questões que quiseres e sentires que podes estudar sem solavancos - desde
+ que sejam questões que possam ser esclarecidas por mensagem. Caso contrário marcamos uma explicação. Durante as explicações também terás comentários em tempo real
+ acerca do trabalho que estiveres a fazer.
+
+
+
+
+
+
+
+ Tudo o que precisas para seres um aluno de sucesso
+
+
+ Além de teres acesso a um explicador especializado,aprenderás a organizar teu tempo, materiais e sessões de estudo, para poderes entregar os trabalhos dentro do prazo
+ e com a qualidade necessária para obteres as melhores notas.
+
+
+
+
+ {features.map(feature => (
+
+
+
+ {feature.name}
+
+
+
{feature.description}
+
+
+ ))}
+
+
+
+
+
+
+
+
+ Sobre o André, o teu explicador de {name}
+
+
+ O André tem vindo a trabalhar como engenheiro de software, há mais de {new Date().getFullYear() - 2006} anos, com empresas como a Fundação Calouste
+ Gulbenkian, a rede de televisão americana NBC, a marca de bebidas Monster Energy e outras empresas de grande escala. Ele tem fornecido apoio em engenharia a
+ inúmeras startups e gerido equipas de mais de 20 pessoas. Atualmente dá formação a alunos universitários, engenheiros de software, equipas de desenvolvimento
+ para melhorarem a qualidade do seu trabalho e o seu curso Mastery for VS Code foi elogiado e destacado pela Microsoft. Ensinar e ajudar pessoas a
+ transformarem-se sempre foi a sua paixão e é por isso que ao longo da sua carreira obteve comentários notáveis.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ As disciplinas que ensino
+
+
+ Ensino engenharia e ciência da computação há mais de {new Date().getFullYear() - 2006} anos, então dominei algumas matérias. Abaixo podes encontrar uma lista
+ (não exaustiva) dos assuntos nos quais te posso ajudar.
+
+
+
+
+
+ {stats.map(stat => (
+
+
+ {stat.name}
+
+
+
+ {stat.value}
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
Programação
+
+ {subjectsITeach.programming.map(item => (
+
+ {item.name}
+
+ ))}
+
+
+
+
Desenvolvimento Web
+
+ {subjectsITeach.webdev.map(item => (
+
+ {item.name}
+
+ ))}
+
+
+
+
+
+
Ciência da Computação
+
+ {subjectsITeach.computerscience.map(item => (
+
+ {item.name}
+
+ ))}
+
+
+
+
Matemática
+
+ {subjectsITeach.math.map(item => (
+
+ {item.name}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ Testemunhos dos alunos incríveis com quem trabalhei
+
+ Cobro 40€ por hora. Os pagamentos são feitos por sessão ou através de subscrição mensal.
+
+
+
+
+
Sessão única
+
+ Precisa de ajuda com um único projeto ou exame? Agende quantas dessas sessões desejar.
+
+
+
+ Podemos usar esse tempo para
+
+
+
+
+ {singleSessionFeatures.map(feature => (
+
+
+ {feature}
+
+ ))}
+
+
+
+
+
+
+ Pague por hora
+
+
+
+ €40
+
+
+ EUR
+
+
+
+
+
+
+
+
+
+
Suporte contínuo 2h/semana
+
+ Estes são os planos mais populares para estudantes que desejam suporte contínuo.
+
+
+
+ Podemos usar esse tempo para
+
+
+
+
+ {includedFeatures.map(feature => (
+
+
+ {feature}
+
+ ))}
+
+
+
+
+
+
+ Subscrição mensal
+
+
+
+ €320
+
+
+ EUR
+
+
+
+
+ Assine e cancele a qualquer momento.
+
+
+
+
+
+
+
+
Suporte contínuo 4h/semana
+
+ Estes são os planos mais populares para estudantes que desejam ótimas notas.
+
+
+
+ Podemos usar esse tempo para
+
+
+
+
+ {includedFeatures.map(feature => (
+
+
+ {feature}
+
+ ))}
+
+
+
+
+
+
+ Subscrição mensal
+
+
+
+ €640
+
+
+ EUR
+
+
+
+
+ Assine e cancele a qualquer momento.
+
+
+
+
+
+
+
+
Suporte contínuo 6h/semana
+
+ Estes são os planos mais populares para estudantes que desejam notas excelentes.
+
+
+
+ Podemos usar esse tempo para
+
+
+
+
+ {includedFeatures.map(feature => (
+
+
+ {feature}
+
+ ))}
+
+
+
+
+
+
+ Subscrição mensal
+
+
+
+ €960
+
+
+ EUR
+
+
+
+
+ Assine e cancele a qualquer momento.
+
+
+
+
+
+
+
+
Suporte contínuo 8h/semana
+
+ Esses são os planos mais populares para estudantes que desejam as melhores notas.
+
+
+
+ Podemos usar esse tempo para
+
+
+
+
+ {includedFeatures.map(feature => (
+
+
+ {feature}
+
+ ))}
+
+
+
+
+
+
+ Subscrição mensal
+
+
+
+ €1280
+
+
+ EUR
+
+
+
+
+ Assine e cancele a qualquer momento.
+
+
+
+
+
+
+
+
+
+
+
+ Selo de garantia de satisfação
+
+
+ Tenho certeza que vais adorar as sessões de tutoria comigo. Na remota possibilidade de não gostares - e tenho orgulho de dizer que em{' '}
+ {new Date().getFullYear() - 2006} anos de aulas particulares, ninguém pediu o dinheiro de volta - eu devolverei o teu dinheiro.
+
+
+
+
+
+
+
+
+
+
+
+ Uma nota para ti
+
+
+ Só quero agradecer-te por reservares um tempo para leres sobre meu serviço de tutoria. Continua a ser uma tremenda honra ter tantos alunos que confiam em mim para
+ ajudá-los a encontrar uma maneira melhor de frequentar a faculdade. Sinceramente espero que tenhas decidido ter tutoria de programação, mesmo que não comigo,
+ porque sei que é uma decisão muito boa.
+
+
+ Ao teu sucesso! 🥂
+
+
+
+
+
+
+
+
+ >
+ )
+}
+export default Route
+
+const newsletterSchema = z.object({ email: emailSchema })
+export const verificationType = `resources`
+
+export async function action({ request, params }: ActionArgs) {
+ const { subjectslug } = params
+ const subject = subjects.find(s => s.slug === subjectslug)!
+ const { name } = subject
+ const formData = await request.formData()
+
+ // Check for bots
+ await validateCSRF(formData, request.headers)
+ checkHoneypot(formData, '/newsletter')
+
+ // Parse form
+ const submission = parse(formData, { schema: newsletterSchema })
+ if (submission.intent !== 'submit') {
+ return json({ status: 'error', submission } as const)
+ }
+ if (!submission.value) {
+ return json({ status: 'error', submission } as const, { status: 400 })
+ }
+
+ // Extract data
+ const { email } = submission.value
+
+ const resourcesURL = new URL(`${getDomainUrl(request)}/explicacoes/${subjectslug}/recursos`)
+ resourcesURL.searchParams.set('email', email)
+
+ const oneDay = 60 * 60 * 24 // One day in seconds
+ const target = email
+ const { otp, secret, algorithm, period, digits } = generateTOTP({ algorithm: 'sha256', period: oneDay })
+ // delete old verifications. Users should not have more than one verification
+ // of a specific type for a specific target at a time.
+ await prisma.verification.deleteMany({
+ where: { type: verificationType, target },
+ })
+ await prisma.verification.create({
+ data: {
+ type: verificationType,
+ target,
+ algorithm,
+ secret,
+ period,
+ digits,
+ expiresAt: new Date(Date.now() + period * 1000),
+ },
+ })
+
+ // add the otp to the url we'll email the user.
+ resourcesURL.searchParams.set('code', otp)
+
+ // Schedule emails
+ await scheduleEmailSequence(email)
+
+ // Send email with resource link
+ await sendEmail({
+ to: email,
+ subject: `🚀 Recursos para estudantes de ${name}`,
+ react: ,
+ })
+
+ // Everything ok
+ return json({ status: 'success', submission } as const)
+}
+
+async function scheduleEmailSequence(email: string) {
+ const now = new Date()
+ const in1Day = new Date(now.getTime() + 1 * 24 * 3600 * 1000)
+ const in2Days = new Date(now.getTime() + 2 * 24 * 3600 * 1000)
+ const in3Days = new Date(now.getTime() + 3 * 24 * 3600 * 1000)
+ const in4Days = new Date(now.getTime() + 4 * 24 * 3600 * 1000)
+ const scheduleDates = [in1Day, in2Days, in3Days, in4Days]
+ for (let i = 0; i < scheduleDates.length; i++) {
+ const scheduledAt = scheduleDates[i]
+ const sequence = i + 1
+ await prisma.emailSchedule.upsert({
+ where: {
+ to_sequence: {
+ to: email,
+ sequence,
+ },
+ },
+ update: {
+ scheduledAt: scheduledAt,
+ },
+ create: {
+ to: email,
+ sequence,
+ scheduledAt: scheduledAt,
+ },
+ })
+ }
+}
diff --git a/app/routes/_marketing+/_pseo+/materia+/$subjectslug_.recursos.tsx b/app/routes/_marketing+/_pseo+/materia+/$subjectslug_.recursos.tsx
new file mode 100644
index 0000000..3cbb5a7
--- /dev/null
+++ b/app/routes/_marketing+/_pseo+/materia+/$subjectslug_.recursos.tsx
@@ -0,0 +1,110 @@
+import { type LoaderArgs, json, redirect } from '@remix-run/node'
+import { subjects } from '../disciplinas.ts'
+import { useLoaderData } from '@remix-run/react'
+import { parse } from '@conform-to/zod'
+import { z } from 'zod'
+import { emailSchema } from '~/utils/user-validation.ts'
+import { prisma } from '~/utils/db.server.ts'
+import { verificationType } from '../explicacoes+/$subjectslug.tsx'
+import { verifyTOTP } from '~/utils/totp.server.ts'
+import { Container } from '~/ui_components/layout/container.tsx'
+import { H1 } from '~/ui_components/typography/h1.tsx'
+import { P } from '~/ui_components/typography/p.tsx'
+
+const verifySchema = z.object({
+ email: emailSchema,
+ code: z.string().min(6).max(6),
+})
+
+export async function loader({ params, request }: LoaderArgs) {
+ const searchParams = new URL(request.url).searchParams
+ if (!searchParams.has('code')) {
+ return redirect('/')
+ }
+ const submission = await parse(searchParams, {
+ schema: () =>
+ verifySchema.superRefine(async (data, ctx) => {
+ const verification = await prisma.verification.findFirst({
+ where: {
+ type: verificationType,
+ target: data.email,
+ expiresAt: { gt: new Date() },
+ },
+ select: {
+ algorithm: true,
+ secret: true,
+ period: true,
+ },
+ })
+ if (!verification) {
+ ctx.addIssue({
+ path: ['code'],
+ code: z.ZodIssueCode.custom,
+ message: `Invalid code`,
+ })
+ return
+ }
+ const result = verifyTOTP({
+ otp: data.code,
+ secret: verification.secret,
+ algorithm: verification.algorithm,
+ period: verification.period,
+ window: 0,
+ })
+ if (!result) {
+ ctx.addIssue({
+ path: ['code'],
+ code: z.ZodIssueCode.custom,
+ message: `Invalid code`,
+ })
+ return
+ }
+ }),
+ acceptMultipleErrors: () => true,
+ async: true,
+ })
+ if (!submission.value) {
+ return redirect('/')
+ }
+ const { subjectslug } = params
+ const subject = subjects.find(s => s.slug === subjectslug)!
+ return json({ subject })
+}
+
+const Route = () => {
+ const {
+ subject: { name, resources },
+ } = useLoaderData()
+ return (
+
+
+
+
+
+ Recursos de {name}
+
+
+ Aqui estão os recursos que te vão ajudar a aprender {name} de forma mais eficaz.
+