Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f764b1239 | |||
| 0df0baf822 | |||
| 32315e179e | |||
| bd8d5677b4 | |||
| 381b750841 | |||
| 2b413e479a | |||
| a6707fe731 | |||
| 19ad8deb6f | |||
|
|
6e697e40c1 | ||
|
|
b25a39df8c | ||
|
|
be3085ce15 | ||
|
|
ed729b9c8e | ||
| e06815053a |
156
Jenkinsfile
vendored
156
Jenkinsfile
vendored
@@ -1,171 +1,103 @@
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
parameters {
|
||||
booleanParam(name: 'DeployAll', defaultValue: false, description: 'Deploy Site/WS ?')
|
||||
booleanParam(name: 'deploySite', defaultValue: false, description: 'Deploy Site ?')
|
||||
}
|
||||
|
||||
triggers {
|
||||
pollSCM('* * * * *')
|
||||
}
|
||||
|
||||
/*
|
||||
environment {
|
||||
now = new Date().format('yyyyMMdd-HHmm', TimeZone.getTimeZone('UTC'))
|
||||
DOCKER_HOST = 'tcp://192.168.2.20:2375'
|
||||
DOCKER_REGISTRY = 'git.homeware.pt/marco'
|
||||
DOCKER_TAG = "${env.BUILD_ID}"
|
||||
DOCKER_REGISTRY = 'Shini89' //'your-docker-registry.com' // Registro Docker
|
||||
|
||||
REACT_DIR = 'geradoresfe'
|
||||
REACT_DOCKER_IMAGE = 'shini89/geradoresfe:lastest'
|
||||
|
||||
SERVICE_DIR = 'GeradoresService'
|
||||
API_DIR = 'GeradoresWS'
|
||||
API_DOCKER_IMAGE = 'shini89/geradoresws:lastest'
|
||||
}
|
||||
*/
|
||||
|
||||
environment {
|
||||
DOCKER_HOST = 'tcp://192.168.2.20:2375'
|
||||
DOCKER_REGISTRY = 'docker.io/shini89'
|
||||
DOCKER_TAG = "${env.BUILD_ID}" // Tag única para builds
|
||||
REACT_DIR = 'geradoresfe'
|
||||
SERVICE_DIR = 'GeradoresService'
|
||||
API_DIR = 'GeradoresWS'
|
||||
|
||||
REACT_IMAGE = "${DOCKER_REGISTRY}/geradores/fe:${DOCKER_TAG}"
|
||||
WS_IMAGE = "${DOCKER_REGISTRY}/geradores/ws:${DOCKER_TAG}"
|
||||
|
||||
DOCKER_CREDENTIALS_ID = 'docker-registry-creds'
|
||||
KUBECONFIG_CREDENTIALS_ID = 'kubeconfig-jenkins'
|
||||
GIT_CREDENTIALS_ID = '3e806a5c-ee46-49fb-974d-15f3fe2e1d49'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Validate Docker Connection') {
|
||||
|
||||
stage('Preparar Ambiente') {
|
||||
steps {
|
||||
script {
|
||||
echo "Validando conexão com Docker remoto: ${DOCKER_HOST}"
|
||||
// Testa a conexão com o Docker remoto
|
||||
sh 'docker --version'
|
||||
echo "Verificar Docker local"
|
||||
sh 'docker version'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Check for Changes') {
|
||||
stage('Checkout Repositório') {
|
||||
steps {
|
||||
script {
|
||||
def message = ""
|
||||
CodeChanges = currentBuild.changeSets != []
|
||||
if (CodeChanges) {
|
||||
def changeLogSets = currentBuild.changeSets
|
||||
for (int i = 0; i < changeLogSets.size(); i++) {
|
||||
def entries = changeLogSets[i].items
|
||||
for (int j = 0; j < entries.length; j++) {
|
||||
def entry = entries[j]
|
||||
message = message + "<br>Autor: ${entry.author.fullName} ( ${entry.author} ) <br> Commit: ${entry.msg}"
|
||||
def files = new ArrayList(entry.affectedFiles)
|
||||
message = message + '<br>Ficheiros:<br><ul>'
|
||||
for (int k = 0; k < files.size(); k++) {
|
||||
def file = files[k]
|
||||
message = message + "<li> ${file.path} ( ${file.editType.name} ) </li>"
|
||||
}
|
||||
message = message + '</ul>'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
git branch: 'master',
|
||||
url: 'https://git.homeware.pt/Marco/Geradores.git',
|
||||
credentialsId: env.GIT_CREDENTIALS_ID
|
||||
}
|
||||
}
|
||||
|
||||
stage('Checkout Code') {
|
||||
stage('Build .NET Services') {
|
||||
steps {
|
||||
git branch: 'master', url: 'https://git.homeware.pt/Marco/Geradores.git'
|
||||
dir("${SERVICE_DIR}") {
|
||||
sh 'dotnet build -c Release'
|
||||
}
|
||||
}
|
||||
/*******************************************************
|
||||
Stage BUILD
|
||||
*******************************************************/
|
||||
stage('Build DLL') {
|
||||
steps {
|
||||
dir("${env.SERVICE_DIR}") {
|
||||
dir("${API_DIR}") {
|
||||
sh 'dotnet build -c Release'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build WS') {
|
||||
stage('Build React App') {
|
||||
steps {
|
||||
dir("${env.API_DIR}") {
|
||||
sh 'dotnet build -c Release'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build WS Docker Image') {
|
||||
steps {
|
||||
script {
|
||||
docker.build("${DOCKER_REGISTRY}/geradoresws:${DOCKER_TAG}", "-f ${API_DIR}/Dockerfile .")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build React') {
|
||||
steps {
|
||||
dir("${env.REACT_DIR}") {
|
||||
dir("${REACT_DIR}") {
|
||||
sh 'npm install'
|
||||
sh 'npm run build'
|
||||
|
||||
/*
|
||||
sh """
|
||||
docker build -t ${env.DOCKER_REGISTRY}/react-frontend:latest .
|
||||
docker push ${env.DOCKER_REGISTRY}/react-frontend:latest
|
||||
"""*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build React Docker Image') {
|
||||
steps {
|
||||
dir("${env.REACT_DIR}") {
|
||||
script {
|
||||
docker.build("${DOCKER_REGISTRY}/geradoresfe:${DOCKER_TAG}", ".")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Push Docker Images') {
|
||||
stage('Docker Build Imagens') {
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('https://index.docker.io/v1/', 'docker-credentials') {
|
||||
docker.image("${DOCKER_REGISTRY}/geradoresws:${DOCKER_TAG}").push()
|
||||
docker.image("${DOCKER_REGISTRY}/geradoresfe:${DOCKER_TAG}").push()
|
||||
}
|
||||
docker.build("${WS_IMAGE}")
|
||||
docker.build("${REACT_IMAGE}", "${REACT_DIR}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Containers Locally') {
|
||||
stage('Push para Docker Registry') {
|
||||
steps {
|
||||
script {
|
||||
// Remove contêiner antigo (se existir)
|
||||
sh """
|
||||
docker rm -f geradoresws-container || true
|
||||
docker rm -f geradoresfe-container || true
|
||||
"""
|
||||
docker.withRegistry("https://${DOCKER_REGISTRY}", GIT_CREDENTIALS_ID) {
|
||||
docker.image("${WS_IMAGE}").push()
|
||||
docker.image("${REACT_IMAGE}").push()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Executa contêineres com as novas imagens
|
||||
stage('Deploy no Kubernetes') {
|
||||
steps {
|
||||
withKubeConfig(credentialsId: KUBECONFIG_CREDENTIALS_ID) {
|
||||
script {
|
||||
// Substitui as imagens no manifest e aplica
|
||||
sh """
|
||||
docker run -d --name geradoresws-container -p 32772:8080 ${DOCKER_REGISTRY}/geradoresws:${DOCKER_TAG}
|
||||
docker run -d --name geradoresfe-container -p 3000:3000 ${DOCKER_REGISTRY}/geradoresfe:${DOCKER_TAG}
|
||||
sed 's|{{WS_IMAGE}}|${WS_IMAGE}|g; s|{{FE_IMAGE}}|${REACT_IMAGE}|g' k8s/deployment.template.yaml > k8s/deployment.yaml
|
||||
kubectl apply -f k8s/deployment.yaml
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
echo 'Services deployed successfully!'
|
||||
echo 'Deploy feito com sucesso!'
|
||||
sh 'docker system prune -f'
|
||||
}
|
||||
failure {
|
||||
echo 'Failed to deploy services. Check logs.'
|
||||
echo 'Erro no pipeline. Verifica os logs!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,6 @@
|
||||
|
||||
<code> docker build -t shini89/geradoresws ..</code>
|
||||
<code> docker run --rm -p 44329:8080 shini89/geradoresws</code>
|
||||
<code>npx swagger-typescript-api generate -p http://localhost:29191/swagger/v1/swagger.json -o src/service -n api.ts --enum-names-as-values</code>
|
||||
|
||||
npx swagger-typescript-api generate -p http://localhost:29191/swagger/v1/swagger.json -o src/service -n api.ts --http-client axios --enum-names-as-values
|
||||
@@ -18,11 +18,11 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
image: docker.io/shini89/geradoresfe:latest
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3000:80"
|
||||
depends_on:
|
||||
- geradoresws
|
||||
environment:
|
||||
- REACT_APP_API_URL=http://localhost:5050/
|
||||
- VITE_API_URL=http://localhost:5050/
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
VITE_API_URL=http://localhost:44329/
|
||||
VITE_API_URL=https://localhost:7266/
|
||||
@@ -1,8 +1,26 @@
|
||||
FROM node:20-alpine
|
||||
# ---------- BUILD ----------
|
||||
FROM node:20-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json .
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
ENV REACT_APP_API_URL=http://localhost:5015/
|
||||
EXPOSE 3000
|
||||
CMD ["npm", "start"]
|
||||
|
||||
# Variável de ambiente correta para Vite
|
||||
ENV VITE_API_URL=http://localhost:5050/
|
||||
RUN npm run build
|
||||
|
||||
# ---------- SERVE ----------
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copia os ficheiros do build para a pasta do nginx
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
# Configuração mínima do nginx (opcional: para SPA fallback)
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
14
geradoresfe/nginx.conf
Normal file
14
geradoresfe/nginx.conf
Normal file
@@ -0,0 +1,14 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri /index.html;
|
||||
}
|
||||
|
||||
# Optional: gzip
|
||||
gzip on;
|
||||
gzip_types text/plain application/javascript text/css application/json image/svg+xml;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
@@ -35,6 +35,7 @@
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"postcss": "^8.5.6",
|
||||
"swagger-typescript-api": "^13.2.7",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.35.1",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import { NIFType } from '../service/api';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
const API_URL = import.meta.env.VITE_API_URL;
|
||||
@@ -8,6 +7,7 @@ const API_URL = import.meta.env.VITE_API_URL;
|
||||
class GeradorService {
|
||||
static async GenerateNIF(type: string | null): Promise<any[]> {
|
||||
try {
|
||||
debugger;
|
||||
const response: AxiosResponse = await axios.get(API_URL + 'Generate/GenerateNIF',
|
||||
{
|
||||
params: {
|
||||
@@ -15,7 +15,7 @@ class GeradorService {
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
} catch (error : any) {
|
||||
|
||||
toast.error('Error fetching NIF:' + error.message);
|
||||
return [];
|
||||
|
||||
@@ -3,6 +3,9 @@ import { Toaster } from 'react-hot-toast';
|
||||
import Home from './pages/Home';
|
||||
import { Layout } from './layout/Layout';
|
||||
import { useTheme } from './context/ThemeContext';
|
||||
import NIF from './pages/NIF';
|
||||
import CC from './pages/CC';
|
||||
import NISS from './pages/NISS';
|
||||
|
||||
function App() {
|
||||
const { theme } = useTheme();
|
||||
@@ -12,9 +15,9 @@ function App() {
|
||||
<Layout>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/NIF" />
|
||||
<Route path="/NISS" />
|
||||
<Route path="/CC" />
|
||||
<Route path="/NIF" element={<NIF />} />
|
||||
<Route path="/NISS" element={<NISS />} />
|
||||
<Route path="/CC" element={<CC />} />
|
||||
</Routes>
|
||||
<Toaster position="top-right"
|
||||
toastOptions={{
|
||||
@@ -22,8 +25,7 @@ function App() {
|
||||
background: theme === 'dark' ? '#1f2937' : '#fff',
|
||||
color: theme === 'dark' ? '#fff' : '#000',
|
||||
},
|
||||
}}
|
||||
theme={theme} />
|
||||
}} />
|
||||
</Layout>
|
||||
</Router>
|
||||
);
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import React, { useState } from "react";
|
||||
// src/components/Geradores/GeradorCard.tsx
|
||||
import { useCallback, useState } from "react";
|
||||
import { RefreshCwIcon, CopyIcon } from "lucide-react";
|
||||
import { Button } from "../ui/Button";
|
||||
import { Input } from "../ui/Input";
|
||||
import { Select } from "../ui/Select";
|
||||
import { ResultDisplay } from "../ui/ResultDisplay";
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { toast } from "react-hot-toast";
|
||||
|
||||
type Parametro =
|
||||
| { nome: string; tipo: "text" | "number" | "password"; placeholder?: string }
|
||||
| { nome: string; tipo: "select"; options: { label: string; value: string }[] };
|
||||
export type Parametro =
|
||||
| { nome: string; tipo: "text" | "number" | "password"; placeholder?: string; default?: string }
|
||||
| { nome: string; tipo: "select"; options: { label: string; value: string }[]; default?: string };
|
||||
|
||||
type GeradorCardProps = {
|
||||
export type GeradorCardProps = {
|
||||
readonly titulo: string;
|
||||
readonly descricao?: string;
|
||||
readonly parametros?: Parametro[];
|
||||
@@ -25,50 +26,92 @@ export default function GeradorCard({
|
||||
onGerar,
|
||||
onValidar,
|
||||
}: GeradorCardProps) {
|
||||
const [resultado, setResultado] = useState("");
|
||||
const [paramInputs, setParamInputs] = useState<Record<string, string>>({});
|
||||
const [validado, setValidado] = useState<boolean | null>(null);
|
||||
|
||||
const handleInputChange = (nome: string, valor: string) => {
|
||||
setParamInputs((prev) => ({ ...prev, [nome]: valor }));
|
||||
};
|
||||
|
||||
const handleGerar = async () => {
|
||||
const gerado = await onGerar(paramInputs);
|
||||
setResultado(gerado);
|
||||
setValidado(null);
|
||||
};
|
||||
|
||||
const handleValidar = async () => {
|
||||
if (onValidar) {
|
||||
const isValid = await onValidar(resultado);
|
||||
setValidado(isValid);
|
||||
// Inicializa paramInputs com defaults vindos de `parametros`
|
||||
const initialParamInputs = parametros.reduce<Record<string, string>>((acc, p) => {
|
||||
debugger;
|
||||
if (p.default) {
|
||||
acc[p.nome] = p.default;
|
||||
} else {
|
||||
acc[p.nome] = "";
|
||||
}
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const handleCopiar = () => {
|
||||
const [resultado, setResultado] = useState("");
|
||||
const [paramInputs, setParamInputs] = useState<Record<string, string>>(initialParamInputs);
|
||||
const [validado, setValidado] = useState<boolean | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleInputChange = useCallback((nome: string, valor: string) => {
|
||||
setParamInputs((prev) => ({ ...prev, [nome]: valor }));
|
||||
}, []);
|
||||
|
||||
const handleGerar = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setValidado(null);
|
||||
try {
|
||||
const gerado = await onGerar(paramInputs);
|
||||
setResultado(typeof gerado === "string" ? gerado : String(gerado ?? ""));
|
||||
toast.success(`${titulo} gerado com sucesso.`, { duration: 2000 });
|
||||
} catch (err) {
|
||||
console.error("Erro ao gerar:", err);
|
||||
toast.error("Falha ao gerar. Tente novamente.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [onGerar, paramInputs, titulo]);
|
||||
|
||||
const handleValidar = useCallback(async () => {
|
||||
if (!onValidar) return;
|
||||
if (!resultado) {
|
||||
toast.error("Nenhum valor para validar.");
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const isValid = await onValidar(resultado);
|
||||
setValidado(Boolean(isValid));
|
||||
if (isValid) {
|
||||
toast.success("Válido", { duration: 1500 });
|
||||
} else {
|
||||
toast.error("Inválido", { duration: 1500 });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Erro ao validar:", err);
|
||||
toast.error("Falha na validação. Tente novamente.");
|
||||
setValidado(null);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [onValidar, resultado]);
|
||||
|
||||
const handleCopiar = useCallback(async () => {
|
||||
if (!resultado) return;
|
||||
navigator.clipboard.writeText(resultado);
|
||||
toast.success(`${titulo} copiado!`,
|
||||
{
|
||||
duration: 3000
|
||||
});
|
||||
};
|
||||
try {
|
||||
await navigator.clipboard.writeText(resultado);
|
||||
toast.success(`${titulo} copiado!`, { duration: 2000 });
|
||||
} catch (err) {
|
||||
console.error("Erro ao copiar:", err);
|
||||
toast.error("Não foi possível copiar para a área de transferência.");
|
||||
}
|
||||
}, [resultado, titulo]);
|
||||
|
||||
const handleResultadoChange = (valor: string) => {
|
||||
const handleResultadoChange = useCallback((valor: string) => {
|
||||
setResultado(valor);
|
||||
setValidado(null); // resetar estado de validação ao editar
|
||||
};
|
||||
setValidado(null); // reset ao editar
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md rounded-2xl border border-gray-200 bg-white dark:bg-zinc-900 p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
|
||||
{/* Título e descrição */}
|
||||
<div
|
||||
className="w-full max-w-md rounded-2xl border border-gray-200 bg-white dark:bg-zinc-900 p-6 shadow-lg hover:shadow-xl transition-shadow duration-300"
|
||||
aria-busy={loading}
|
||||
>
|
||||
<div className="mb-6">
|
||||
<h3 className="text-xl font-bold text-blue-700 dark:text-blue-400">{titulo}</h3>
|
||||
{descricao && <p className="text-sm text-gray-600 dark:text-gray-400 mt-1">{descricao}</p>}
|
||||
</div>
|
||||
|
||||
{/* Parâmetros dinâmicos */}
|
||||
{parametros.length > 0 && (
|
||||
<div className="space-y-4 mb-6">
|
||||
{parametros.map((param) => {
|
||||
@@ -78,9 +121,10 @@ export default function GeradorCard({
|
||||
key={param.nome}
|
||||
label={param.nome}
|
||||
options={param.options}
|
||||
value={paramInputs[param.nome] || ""}
|
||||
value={paramInputs[param.nome] ?? ""}
|
||||
onChange={(val) => handleInputChange(param.nome, val)}
|
||||
placeholder={`Selecionar ${param.nome}`}
|
||||
aria-label={param.nome}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -90,21 +134,23 @@ export default function GeradorCard({
|
||||
key={param.nome}
|
||||
type={param.tipo}
|
||||
placeholder={param.placeholder || param.nome}
|
||||
value={paramInputs[param.nome] || ""}
|
||||
value={paramInputs[param.nome] ?? ""}
|
||||
onChange={(e) => handleInputChange(param.nome, e.target.value)}
|
||||
aria-label={param.nome}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Resultado + botão de copiar como ícone */}
|
||||
<div className="mb-6 flex items-center gap-2 relative">
|
||||
<ResultDisplay
|
||||
value={resultado}
|
||||
validated={validado}
|
||||
onChange={handleResultadoChange}
|
||||
aria-label={`${titulo} resultado`}
|
||||
/>
|
||||
|
||||
{resultado && (
|
||||
<Button
|
||||
onClick={handleCopiar}
|
||||
@@ -112,25 +158,31 @@ export default function GeradorCard({
|
||||
variant="secondary"
|
||||
className="flex items-center gap-1 px-2 py-1 text-xs h-auto"
|
||||
title="Copiar"
|
||||
>
|
||||
</Button>
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Botões distribuídos numa linha com preenchimento igual */}
|
||||
<div className="flex w-full gap-x-2">
|
||||
<Button
|
||||
onClick={handleGerar}
|
||||
icon={<RefreshCwIcon className="w-4 h-4" />}
|
||||
variant="primary"
|
||||
className="flex-1"
|
||||
title={`Gerar ${titulo}`}
|
||||
disabled={loading}
|
||||
>
|
||||
Gerar
|
||||
{loading ? "A gerar..." : "Gerar"}
|
||||
</Button>
|
||||
|
||||
{onValidar && (
|
||||
<Button onClick={handleValidar} variant="danger" className="flex-1">
|
||||
Validar
|
||||
<Button
|
||||
onClick={handleValidar}
|
||||
variant={validado === true ? "primary" : "danger"}
|
||||
className="flex-1"
|
||||
title={`Validar ${titulo}`}
|
||||
disabled={loading || !resultado}
|
||||
>
|
||||
{loading ? "Verificando..." : "Validar"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import GeradorCard from "../GeradorCard";
|
||||
import { EnumToOptions } from "../../../library/utils";
|
||||
import GeradorCard, { type Parametro } from "../GeradorCard";
|
||||
import { EnumToOptions, getEnumKeyByValue } from "../../../library/utils";
|
||||
import { NIFType } from "../../../service/api";
|
||||
import GeradorService from "../../../Api/GeradorApi";
|
||||
|
||||
@@ -10,31 +9,31 @@ const NifTypes = EnumToOptions(NIFType).map((opt) => ({
|
||||
}));
|
||||
|
||||
const GenerateNIF = () => {
|
||||
|
||||
const handleGenerateNIF = async (params: Record<string, string>) => {
|
||||
const tipoSelecionado = params["Tipo de NIF"];
|
||||
const nif = await GeradorService.GenerateNIF(tipoSelecionado);
|
||||
|
||||
const handleGenerateNIF = async (params?: Record<string, string>) => {
|
||||
const tipoSelecionado = params?.["Tipo de NIF"] ?? String(NIFType.PessoaSingular2);
|
||||
const nif = String(await GeradorService.GenerateNIF(tipoSelecionado));
|
||||
return nif;
|
||||
};
|
||||
|
||||
const handleValidateNIF = async (valor: string) => {
|
||||
// Lógica real de validação
|
||||
const bol = await GeradorService.ValidateNIF(valor);
|
||||
const bol = Boolean(await GeradorService.ValidateNIF(valor));
|
||||
return bol;
|
||||
};
|
||||
|
||||
const parametros: Parametro[] = [
|
||||
{
|
||||
nome: "Tipo de NIF",
|
||||
tipo: "select",
|
||||
options: NifTypes,
|
||||
default: getEnumKeyByValue(NIFType, NIFType.PessoaSingular2)
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="max-w-md mx-auto p-6">
|
||||
<GeradorCard
|
||||
titulo="NIF"
|
||||
parametros={[
|
||||
{
|
||||
nome: "Tipo de NIF",
|
||||
tipo: "select",
|
||||
options: NifTypes,
|
||||
},
|
||||
]}
|
||||
parametros={parametros}
|
||||
onGerar={handleGenerateNIF}
|
||||
onValidar={handleValidateNIF}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import GeradorService from "../../../Api/GeradorApi";
|
||||
import GeradorCard from "../GeradorCard.tsx";
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function Footer() {
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/geradores" className="hover:text-blue-500 dark:hover:text-blue-400 transition-colors duration-200">
|
||||
<Link to="/home" className="hover:text-blue-500 dark:hover:text-blue-400 transition-colors duration-200">
|
||||
Geradores
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
@@ -10,8 +10,9 @@ const navItems = [
|
||||
{
|
||||
name: "Geradores",
|
||||
subItems: [
|
||||
{ name: "Gerador de Senhas", path: "/geradores/senhas" },
|
||||
{ name: "Gerador de Nomes", path: "/geradores/nomes" },
|
||||
{ name: "Gerador de NIFs", path: "/NIF", },
|
||||
{ name: "Gerador de NISS", path: "/NISS" },
|
||||
{ name: "Gerador de CC", path: "/CC" },
|
||||
],
|
||||
},
|
||||
{ name: "Contacto", path: "/contacto" },
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// components/layout/Layout.tsx
|
||||
import Footer from './Footer';
|
||||
import Header from './Header';
|
||||
import { useTheme } from "../context/ThemeContext"; // caminho conforme a tua estrutura
|
||||
|
||||
export const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
|
||||
const Utils = {
|
||||
EnumToOptions,
|
||||
// Outras fun<75><6E>es podem ser adicionadas aqui
|
||||
// Outras fun<75><6E>es podem ser adicionadas aqui
|
||||
};
|
||||
|
||||
export function EnumToOptions<T extends Record<string, string>>(enumObj: T): any[] {
|
||||
return Object.entries(enumObj)
|
||||
.filter(([key]) => isNaN(Number(key))) // Ignora entradas num<75>ricas, caso existam
|
||||
.filter(([key]) => isNaN(Number(key))) // Ignora entradas num<75>ricas, caso existam
|
||||
.map(([key, value]) => ({
|
||||
value: key, // A chave do enum como `value`
|
||||
label: value, // O valor do enum como `label`
|
||||
}));
|
||||
}
|
||||
|
||||
export function getEnumKeyByValue<T extends Record<string, string>>(
|
||||
enumObj: T,
|
||||
value: string
|
||||
): string | undefined {
|
||||
return Object.keys(enumObj).find((key) => enumObj[key as keyof T] === value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import React from "react";
|
||||
|
||||
|
||||
export default function Blank() {
|
||||
console.log("inicalizar componente");
|
||||
return (
|
||||
|
||||
31
geradoresfe/src/pages/CC.tsx
Normal file
31
geradoresfe/src/pages/CC.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from "react";
|
||||
import { useLocation } from "react-router";
|
||||
import GenerateCC from "../components/Geradores/Tipos/GenerateCC";
|
||||
|
||||
export default function CC() {
|
||||
const location = useLocation();
|
||||
|
||||
// Efeito para rolar até a seção correspondente ao path
|
||||
useEffect(() => {
|
||||
const featuresSection = document.getElementById(location.hash.substring(1));
|
||||
if (featuresSection) {
|
||||
featuresSection.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
|
||||
}, [location]);
|
||||
|
||||
return (
|
||||
<div >
|
||||
<div >
|
||||
{/* Seção de Funcionalidades */}
|
||||
<section id="features" className="py-16 px-4 md:px-8">
|
||||
<div className="max-w-6xl mx-auto grid grid-cols-1">
|
||||
<div id="nif">
|
||||
<GenerateCC />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
geradoresfe/src/pages/NIF.tsx
Normal file
31
geradoresfe/src/pages/NIF.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from "react";
|
||||
import { useLocation } from "react-router";
|
||||
import GenerateNIF from "../components/Geradores/Tipos/GenerateNIF";
|
||||
|
||||
export default function NIF() {
|
||||
const location = useLocation();
|
||||
|
||||
// Efeito para rolar até a seção correspondente ao path
|
||||
useEffect(() => {
|
||||
const featuresSection = document.getElementById(location.hash.substring(1));
|
||||
if (featuresSection) {
|
||||
featuresSection.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
|
||||
}, [location]);
|
||||
|
||||
return (
|
||||
<div >
|
||||
<div >
|
||||
{/* Seção de Funcionalidades */}
|
||||
<section id="features" className="py-16 px-4 md:px-8">
|
||||
<div className="max-w-6xl mx-auto grid grid-cols-1">
|
||||
<div id="nif">
|
||||
<GenerateNIF />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
geradoresfe/src/pages/NISS.tsx
Normal file
31
geradoresfe/src/pages/NISS.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from "react";
|
||||
import { useLocation } from "react-router";
|
||||
import GenerateNISS from "../components/Geradores/Tipos/GenerateNISS";
|
||||
|
||||
export default function NISS() {
|
||||
const location = useLocation();
|
||||
|
||||
// Efeito para rolar até a seção correspondente ao path
|
||||
useEffect(() => {
|
||||
const featuresSection = document.getElementById(location.hash.substring(1));
|
||||
if (featuresSection) {
|
||||
featuresSection.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
|
||||
}, [location]);
|
||||
|
||||
return (
|
||||
<div >
|
||||
<div >
|
||||
{/* Seção de Funcionalidades */}
|
||||
<section id="features" className="py-16 px-4 md:px-8">
|
||||
<div className="max-w-6xl mx-auto grid grid-cols-1">
|
||||
<div id="nif">
|
||||
<GenerateNISS />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable */
|
||||
/* tslint:disable */
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* ---------------------------------------------------------------
|
||||
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
|
||||
@@ -10,12 +11,19 @@
|
||||
*/
|
||||
|
||||
export enum NIFType {
|
||||
/** Pessoa singular (1) */
|
||||
PessoaSingular1 = "Pessoa singular (1)",
|
||||
/** Pessoa singular (2) */
|
||||
PessoaSingular2 = "Pessoa singular (2)",
|
||||
/** Pessoa singular (3; novo em 2019) */
|
||||
PessoaSingular3 = "Pessoa singular (3; novo em 2019)",
|
||||
/** Pessoa colectiva (5) */
|
||||
PessoaColectiva = "Pessoa colectiva (5)",
|
||||
/** Pessoa colectiva pública (6) */
|
||||
PessoaColectivaPublica = "Pessoa colectiva pública (6)",
|
||||
/** Empresário em nome individual (8) */
|
||||
EmpresarioIndividual = "Empresário em nome individual (8)",
|
||||
/** Pessoa colectiva irregular ou número provisório (9) */
|
||||
PessoaColectivaIrregular = "Pessoa colectiva irregular ou número provisório (9)",
|
||||
}
|
||||
|
||||
@@ -29,10 +37,19 @@ export interface WeatherForecast {
|
||||
summary?: string | null;
|
||||
}
|
||||
|
||||
export type QueryParamsType = Record<string | number, any>;
|
||||
export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
|
||||
import type {
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
HeadersDefaults,
|
||||
ResponseType,
|
||||
} from "axios";
|
||||
import axios from "axios";
|
||||
|
||||
export interface FullRequestParams extends Omit<RequestInit, "body"> {
|
||||
export type QueryParamsType = Record<string | number, any>;
|
||||
|
||||
export interface FullRequestParams
|
||||
extends Omit<AxiosRequestConfig, "data" | "params" | "url" | "responseType"> {
|
||||
/** set parameter to `true` for call `securityWorker` for this request */
|
||||
secure?: boolean;
|
||||
/** request path */
|
||||
@@ -42,199 +59,155 @@ export interface FullRequestParams extends Omit<RequestInit, "body"> {
|
||||
/** query params */
|
||||
query?: QueryParamsType;
|
||||
/** format of response (i.e. response.json() -> format: "json") */
|
||||
format?: ResponseFormat;
|
||||
format?: ResponseType;
|
||||
/** request body */
|
||||
body?: unknown;
|
||||
/** base url */
|
||||
baseUrl?: string;
|
||||
/** request cancellation token */
|
||||
cancelToken?: CancelToken;
|
||||
}
|
||||
|
||||
export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">;
|
||||
export type RequestParams = Omit<
|
||||
FullRequestParams,
|
||||
"body" | "method" | "query" | "path"
|
||||
>;
|
||||
|
||||
export interface ApiConfig<SecurityDataType = unknown> {
|
||||
baseUrl?: string;
|
||||
baseApiParams?: Omit<RequestParams, "baseUrl" | "cancelToken" | "signal">;
|
||||
securityWorker?: (securityData: SecurityDataType | null) => Promise<RequestParams | void> | RequestParams | void;
|
||||
customFetch?: typeof fetch;
|
||||
export interface ApiConfig<SecurityDataType = unknown>
|
||||
extends Omit<AxiosRequestConfig, "data" | "cancelToken"> {
|
||||
securityWorker?: (
|
||||
securityData: SecurityDataType | null,
|
||||
) => Promise<AxiosRequestConfig | void> | AxiosRequestConfig | void;
|
||||
secure?: boolean;
|
||||
format?: ResponseType;
|
||||
}
|
||||
|
||||
export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
|
||||
data: D;
|
||||
error: E;
|
||||
}
|
||||
|
||||
type CancelToken = Symbol | string | number;
|
||||
|
||||
export enum ContentType {
|
||||
Json = "application/json",
|
||||
JsonApi = "application/vnd.api+json",
|
||||
FormData = "multipart/form-data",
|
||||
UrlEncoded = "application/x-www-form-urlencoded",
|
||||
Text = "text/plain",
|
||||
}
|
||||
|
||||
export class HttpClient<SecurityDataType = unknown> {
|
||||
public baseUrl: string = "";
|
||||
public instance: AxiosInstance;
|
||||
private securityData: SecurityDataType | null = null;
|
||||
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
|
||||
private abortControllers = new Map<CancelToken, AbortController>();
|
||||
private customFetch = (...fetchParams: Parameters<typeof fetch>) => fetch(...fetchParams);
|
||||
private secure?: boolean;
|
||||
private format?: ResponseType;
|
||||
|
||||
private baseApiParams: RequestParams = {
|
||||
credentials: "same-origin",
|
||||
headers: {},
|
||||
redirect: "follow",
|
||||
referrerPolicy: "no-referrer",
|
||||
};
|
||||
|
||||
constructor(apiConfig: ApiConfig<SecurityDataType> = {}) {
|
||||
Object.assign(this, apiConfig);
|
||||
constructor({
|
||||
securityWorker,
|
||||
secure,
|
||||
format,
|
||||
...axiosConfig
|
||||
}: ApiConfig<SecurityDataType> = {}) {
|
||||
this.instance = axios.create({
|
||||
...axiosConfig,
|
||||
baseURL: axiosConfig.baseURL || "",
|
||||
});
|
||||
this.secure = secure;
|
||||
this.format = format;
|
||||
this.securityWorker = securityWorker;
|
||||
}
|
||||
|
||||
public setSecurityData = (data: SecurityDataType | null) => {
|
||||
this.securityData = data;
|
||||
};
|
||||
|
||||
protected encodeQueryParam(key: string, value: any) {
|
||||
const encodedKey = encodeURIComponent(key);
|
||||
return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
|
||||
}
|
||||
protected mergeRequestParams(
|
||||
params1: AxiosRequestConfig,
|
||||
params2?: AxiosRequestConfig,
|
||||
): AxiosRequestConfig {
|
||||
const method = params1.method || (params2 && params2.method);
|
||||
|
||||
protected addQueryParam(query: QueryParamsType, key: string) {
|
||||
return this.encodeQueryParam(key, query[key]);
|
||||
}
|
||||
|
||||
protected addArrayQueryParam(query: QueryParamsType, key: string) {
|
||||
const value = query[key];
|
||||
return value.map((v: any) => this.encodeQueryParam(key, v)).join("&");
|
||||
}
|
||||
|
||||
protected toQueryString(rawQuery?: QueryParamsType): string {
|
||||
const query = rawQuery || {};
|
||||
const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
|
||||
return keys
|
||||
.map((key) => (Array.isArray(query[key]) ? this.addArrayQueryParam(query, key) : this.addQueryParam(query, key)))
|
||||
.join("&");
|
||||
}
|
||||
|
||||
protected addQueryParams(rawQuery?: QueryParamsType): string {
|
||||
const queryString = this.toQueryString(rawQuery);
|
||||
return queryString ? `?${queryString}` : "";
|
||||
}
|
||||
|
||||
private contentFormatters: Record<ContentType, (input: any) => any> = {
|
||||
[ContentType.Json]: (input: any) =>
|
||||
input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input,
|
||||
[ContentType.Text]: (input: any) => (input !== null && typeof input !== "string" ? JSON.stringify(input) : input),
|
||||
[ContentType.FormData]: (input: any) =>
|
||||
Object.keys(input || {}).reduce((formData, key) => {
|
||||
const property = input[key];
|
||||
formData.append(
|
||||
key,
|
||||
property instanceof Blob
|
||||
? property
|
||||
: typeof property === "object" && property !== null
|
||||
? JSON.stringify(property)
|
||||
: `${property}`,
|
||||
);
|
||||
return formData;
|
||||
}, new FormData()),
|
||||
[ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
|
||||
};
|
||||
|
||||
protected mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams {
|
||||
return {
|
||||
...this.baseApiParams,
|
||||
...this.instance.defaults,
|
||||
...params1,
|
||||
...(params2 || {}),
|
||||
headers: {
|
||||
...(this.baseApiParams.headers || {}),
|
||||
...((method &&
|
||||
this.instance.defaults.headers[
|
||||
method.toLowerCase() as keyof HeadersDefaults
|
||||
]) ||
|
||||
{}),
|
||||
...(params1.headers || {}),
|
||||
...((params2 && params2.headers) || {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => {
|
||||
if (this.abortControllers.has(cancelToken)) {
|
||||
const abortController = this.abortControllers.get(cancelToken);
|
||||
if (abortController) {
|
||||
return abortController.signal;
|
||||
protected stringifyFormItem(formItem: unknown) {
|
||||
if (typeof formItem === "object" && formItem !== null) {
|
||||
return JSON.stringify(formItem);
|
||||
} else {
|
||||
return `${formItem}`;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
const abortController = new AbortController();
|
||||
this.abortControllers.set(cancelToken, abortController);
|
||||
return abortController.signal;
|
||||
};
|
||||
|
||||
public abortRequest = (cancelToken: CancelToken) => {
|
||||
const abortController = this.abortControllers.get(cancelToken);
|
||||
|
||||
if (abortController) {
|
||||
abortController.abort();
|
||||
this.abortControllers.delete(cancelToken);
|
||||
protected createFormData(input: Record<string, unknown>): FormData {
|
||||
if (input instanceof FormData) {
|
||||
return input;
|
||||
}
|
||||
};
|
||||
return Object.keys(input || {}).reduce((formData, key) => {
|
||||
const property = input[key];
|
||||
const propertyContent: any[] =
|
||||
property instanceof Array ? property : [property];
|
||||
|
||||
public request = async <T = any, E = any>({
|
||||
body,
|
||||
for (const formItem of propertyContent) {
|
||||
const isFileType = formItem instanceof Blob || formItem instanceof File;
|
||||
formData.append(
|
||||
key,
|
||||
isFileType ? formItem : this.stringifyFormItem(formItem),
|
||||
);
|
||||
}
|
||||
|
||||
return formData;
|
||||
}, new FormData());
|
||||
}
|
||||
|
||||
public request = async <T = any, _E = any>({
|
||||
secure,
|
||||
path,
|
||||
type,
|
||||
query,
|
||||
format,
|
||||
baseUrl,
|
||||
cancelToken,
|
||||
body,
|
||||
...params
|
||||
}: FullRequestParams): Promise<HttpResponse<T, E>> => {
|
||||
}: FullRequestParams): Promise<AxiosResponse<T>> => {
|
||||
const secureParams =
|
||||
((typeof secure === "boolean" ? secure : this.baseApiParams.secure) &&
|
||||
((typeof secure === "boolean" ? secure : this.secure) &&
|
||||
this.securityWorker &&
|
||||
(await this.securityWorker(this.securityData))) ||
|
||||
{};
|
||||
const requestParams = this.mergeRequestParams(params, secureParams);
|
||||
const queryString = query && this.toQueryString(query);
|
||||
const payloadFormatter = this.contentFormatters[type || ContentType.Json];
|
||||
const responseFormat = format || requestParams.format;
|
||||
const responseFormat = format || this.format || undefined;
|
||||
|
||||
return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, {
|
||||
if (
|
||||
type === ContentType.FormData &&
|
||||
body &&
|
||||
body !== null &&
|
||||
typeof body === "object"
|
||||
) {
|
||||
body = this.createFormData(body as Record<string, unknown>);
|
||||
}
|
||||
|
||||
if (
|
||||
type === ContentType.Text &&
|
||||
body &&
|
||||
body !== null &&
|
||||
typeof body !== "string"
|
||||
) {
|
||||
body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
return this.instance.request({
|
||||
...requestParams,
|
||||
headers: {
|
||||
...(requestParams.headers || {}),
|
||||
...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),
|
||||
...(type ? { "Content-Type": type } : {}),
|
||||
},
|
||||
signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null,
|
||||
body: typeof body === "undefined" || body === null ? null : payloadFormatter(body),
|
||||
}).then(async (response) => {
|
||||
const r = response.clone() as HttpResponse<T, E>;
|
||||
r.data = null as unknown as T;
|
||||
r.error = null as unknown as E;
|
||||
|
||||
const data = !responseFormat
|
||||
? r
|
||||
: await response[responseFormat]()
|
||||
.then((data) => {
|
||||
if (r.ok) {
|
||||
r.data = data;
|
||||
} else {
|
||||
r.error = data;
|
||||
}
|
||||
return r;
|
||||
})
|
||||
.catch((e) => {
|
||||
r.error = e;
|
||||
return r;
|
||||
});
|
||||
|
||||
if (cancelToken) {
|
||||
this.abortControllers.delete(cancelToken);
|
||||
}
|
||||
|
||||
if (!response.ok) throw data;
|
||||
return data;
|
||||
params: query,
|
||||
responseType: responseFormat,
|
||||
data: body,
|
||||
url: path,
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -244,7 +217,9 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
* @version v1
|
||||
* @contact Marco Santos
|
||||
*/
|
||||
export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDataType> {
|
||||
export class Api<
|
||||
SecurityDataType extends unknown,
|
||||
> extends HttpClient<SecurityDataType> {
|
||||
generate = {
|
||||
/**
|
||||
* No description
|
||||
@@ -255,14 +230,7 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
|
||||
*/
|
||||
generateNifList: (
|
||||
query?: {
|
||||
type?:
|
||||
| "Pessoa singular (1)"
|
||||
| "Pessoa singular (2)"
|
||||
| "Pessoa singular (3; novo em 2019)"
|
||||
| "Pessoa colectiva (5)"
|
||||
| "Pessoa colectiva pública (6)"
|
||||
| "Empresário em nome individual (8)"
|
||||
| "Pessoa colectiva irregular ou número provisório (9)";
|
||||
type?: NIFType;
|
||||
},
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
@@ -330,6 +298,21 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
|
||||
format: "json",
|
||||
...params,
|
||||
}),
|
||||
|
||||
/**
|
||||
* No description
|
||||
*
|
||||
* @tags Generate
|
||||
* @name GenerateCcList
|
||||
* @request GET:/Generate/GenerateCC
|
||||
*/
|
||||
generateCcList: (params: RequestParams = {}) =>
|
||||
this.request<string, any>({
|
||||
path: `/Generate/GenerateCC`,
|
||||
method: "GET",
|
||||
format: "json",
|
||||
...params,
|
||||
}),
|
||||
};
|
||||
weatherForecast = {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user