refactor: update packages to React 19, Vite 8 and Tailwind 4 and modernize configs

This commit is contained in:
Marcos
2026-03-23 07:40:32 -03:00
parent c9c7f40a0b
commit 0ad29893d0
17 changed files with 1956 additions and 3514 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{a as p,b as y,c as v}from"./form-vendor-vQotxSmE.js";function g(r,s,o){function e(t,c){var u;Object.defineProperty(t,"_zod",{value:t._zod??{},enumerable:!1}),(u=t._zod).traits??(u.traits=new Set),t._zod.traits.add(r),s(t,c);for(const f in n.prototype)f in t||Object.defineProperty(t,f,{value:n.prototype[f].bind(t)});t._zod.constr=n,t._zod.def=c}const a=o?.Parent??Object;class i extends a{}Object.defineProperty(i,"name",{value:r});function n(t){var c;const u=o?.Parent?new i:this;e(u,t),(c=u._zod).deferred??(c.deferred=[]);for(const f of u._zod.deferred)f();return u}return Object.defineProperty(n,"init",{value:e}),Object.defineProperty(n,Symbol.hasInstance,{value:t=>o?.Parent&&t instanceof o.Parent?!0:t?._zod?.traits?.has(r)}),Object.defineProperty(n,"name",{value:r}),n}class j extends Error{constructor(){super("Encountered Promise during synchronous parse. Use .parseAsync() instead.")}}const z={};function m(r){return z}function w(r,s){return typeof s=="bigint"?s.toString():s}const b=Error.captureStackTrace?Error.captureStackTrace:(...r)=>{};function d(r){return typeof r=="string"?r:r?.message}function E(r,s,o){const e={...r,path:r.path??[]};if(!r.message){const a=d(r.inst?._zod.def?.error?.(r))??d(s?.error?.(r))??d(o.customError?.(r))??d(o.localeError?.(r))??"Invalid input";e.message=a}return delete e.inst,delete e.continue,s?.reportInput||delete e.input,e}const P=(r,s)=>{r.name="$ZodError",Object.defineProperty(r,"_zod",{value:r._zod,enumerable:!1}),Object.defineProperty(r,"issues",{value:s,enumerable:!1}),Object.defineProperty(r,"message",{get(){return JSON.stringify(s,w,2)},enumerable:!0}),Object.defineProperty(r,"toString",{value:()=>r.message,enumerable:!1})},O=g("$ZodError",P),_=g("$ZodError",P,{Parent:Error}),S=r=>(s,o,e,a)=>{const i=e?Object.assign(e,{async:!1}):{async:!1},n=s._zod.run({value:o,issues:[]},i);if(n instanceof Promise)throw new j;if(n.issues.length){const t=new(a?.Err??r)(n.issues.map(c=>E(c,i,m())));throw b(t,a?.callee),t}return n.value},A=S(_),Z=r=>async(s,o,e,a)=>{const i=e?Object.assign(e,{async:!0}):{async:!0};let n=s._zod.run({value:o,issues:[]},i);if(n instanceof Promise&&(n=await n),n.issues.length){const t=new(a?.Err??r)(n.issues.map(c=>E(c,i,m())));throw b(t,a?.callee),t}return n.value},N=Z(_);function h(r,s){try{var o=r()}catch(e){return s(e)}return o&&o.then?o.then(void 0,s):o}function I(r,s){for(var o={};r.length;){var e=r[0],a=e.code,i=e.message,n=e.path.join(".");if(!o[n])if("unionErrors"in e){var t=e.unionErrors[0].errors[0];o[n]={message:t.message,type:t.code}}else o[n]={message:i,type:a};if("unionErrors"in e&&e.unionErrors.forEach(function(f){return f.errors.forEach(function(l){return r.push(l)})}),s){var c=o[n].types,u=c&&c[e.code];o[n]=v(n,s,o,a,u?[].concat(u,e.message):e.message)}r.shift()}return o}function U(r,s){for(var o={};r.length;){var e=r[0],a=e.code,i=e.message,n=e.path.join(".");if(!o[n])if(e.code==="invalid_union"&&e.errors.length>0){var t=e.errors[0][0];o[n]={message:t.message,type:t.code}}else o[n]={message:i,type:a};if(e.code==="invalid_union"&&e.errors.forEach(function(f){return f.forEach(function(l){return r.push(l)})}),s){var c=o[n].types,u=c&&c[e.code];o[n]=v(n,s,o,a,u?[].concat(u,e.message):e.message)}r.shift()}return o}function k(r,s,o){if(o===void 0&&(o={}),(function(e){return"_def"in e&&typeof e._def=="object"&&"typeName"in e._def})(r))return function(e,a,i){try{return Promise.resolve(h(function(){return Promise.resolve(r[o.mode==="sync"?"parse":"parseAsync"](e,s)).then(function(n){return i.shouldUseNativeValidation&&p({},i),{errors:{},values:o.raw?Object.assign({},e):n}})},function(n){if((function(t){return Array.isArray(t?.issues)})(n))return{values:{},errors:y(I(n.errors,!i.shouldUseNativeValidation&&i.criteriaMode==="all"),i)};throw n}))}catch(n){return Promise.reject(n)}};if((function(e){return"_zod"in e&&typeof e._zod=="object"})(r))return function(e,a,i){try{return Promise.resolve(h(function(){return Promise.resolve((o.mode==="sync"?A:N)(r,e,s)).then(function(n){return i.shouldUseNativeValidation&&p({},i),{errors:{},values:o.raw?Object.assign({},e):n}})},function(n){if((function(t){return t instanceof O})(n))return{values:{},errors:y(U(n.issues,!i.shouldUseNativeValidation&&i.criteriaMode==="all"),i)};throw n}))}catch(n){return Promise.reject(n)}};throw new Error("Invalid input: not a Zod schema")}export{k as a};

File diff suppressed because one or more lines are too long

18
dist/index.html vendored
View File

@@ -8,14 +8,16 @@
<meta name="theme-color" content="#2563eb" />
<link rel="manifest" href="/manifest.json" />
<title>RDO Mobile - Relatório Diário de Obra</title>
<script type="module" crossorigin src="/assets/js/index-DXLajEHZ.js"></script>
<link rel="modulepreload" crossorigin href="/assets/js/react-vendor-CqRd3GwO.js">
<link rel="modulepreload" crossorigin href="/assets/js/router-vendor-D4by-_6Z.js">
<link rel="modulepreload" crossorigin href="/assets/js/query-vendor-Dc_G4OIP.js">
<link rel="modulepreload" crossorigin href="/assets/js/ui-vendor-DHNIDV-1.js">
<link rel="modulepreload" crossorigin href="/assets/js/supabase-vendor-By1yMVW6.js">
<link rel="modulepreload" crossorigin href="/assets/js/state-vendor-DK3LaRDK.js">
<link rel="stylesheet" crossorigin href="/assets/css/index-CYCdtjzd.css">
<script type="module" crossorigin src="/assets/index-BFMh0Owy.js"></script>
<link rel="modulepreload" crossorigin href="/assets/react-DtrESx-C.js">
<link rel="modulepreload" crossorigin href="/assets/preload-helper-DSXbuxSR.js">
<link rel="modulepreload" crossorigin href="/assets/supabase-L170XLdN.js">
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-BLxppFDo.js">
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-DNOlzffn.js">
<link rel="modulepreload" crossorigin href="/assets/react-eH9hKoTL.js">
<link rel="modulepreload" crossorigin href="/assets/useUserStore-Btl1TeSc.js">
<link rel="modulepreload" crossorigin href="/assets/useAuth-Bw9Uh8UY.js">
<link rel="stylesheet" crossorigin href="/assets/index-B3UgNpvV.css">
</head>
<body>
<div id="root"></div>

4900
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,54 +16,53 @@
"auto-sync": "node scripts/auto-sync.js"
},
"dependencies": {
"@capacitor/core": "^6.0.0",
"@capacitor/ios": "^6.0.0",
"@hookform/resolvers": "^5.2.1",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-toast": "^1.1.5",
"@supabase/supabase-js": "^2.39.0",
"@tanstack/react-query": "^5.89.0",
"@tanstack/react-query-devtools": "^5.89.0",
"@vitejs/plugin-react": "^4.4.1",
"autoprefixer": "^10.4.21",
"chokidar": "^4.0.3",
"@capacitor/core": "^8.2.0",
"@capacitor/ios": "^8.2.0",
"@hookform/resolvers": "^5.2.2",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-toast": "^1.2.15",
"@supabase/supabase-js": "^2.99.3",
"@tailwindcss/vite": "^4.2.2",
"@tanstack/react-query": "^5.95.0",
"@tanstack/react-query-devtools": "^5.95.0",
"@vitejs/plugin-react": "^6.0.1",
"chokidar": "^5.0.0",
"clsx": "^2.1.1",
"dexie": "^4.2.1",
"dexie": "^4.3.0",
"dexie-react-hooks": "^4.2.0",
"framer-motion": "^10.18.0",
"lucide-react": "^0.511.0",
"framer-motion": "^12.38.0",
"lucide-react": "^0.577.0",
"phosphor-react": "^1.4.1",
"postcss": "^8.5.3",
"qrcode.react": "^4.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.48.2",
"react-router-dom": "^7.3.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-hook-form": "^7.72.0",
"react-router-dom": "^7.13.1",
"sonner": "^2.0.7",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^3.4.17",
"typescript": "~5.8.3",
"vite": "^6.3.5",
"vite-tsconfig-paths": "^5.1.4",
"zod": "^3.22.4",
"zustand": "^5.0.3"
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.2.2",
"typescript": "~5.9.3",
"vite": "^8.0.1",
"vite-tsconfig-paths": "^6.1.1",
"zod": "^4.3.6",
"zustand": "^5.0.12"
},
"devDependencies": {
"@capacitor/cli": "^6.0.0",
"@eslint/js": "^9.25.0",
"@types/node": "^22.15.30",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"babel-plugin-react-dev-locator": "^1.0.0",
"baseline-browser-mapping": "^2.10.0",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"globals": "^16.0.0",
"typescript-eslint": "^8.30.1"
"@capacitor/cli": "^8.2.0",
"@eslint/js": "^10.0.1",
"@types/node": "^25.5.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "^8.57.1",
"@typescript-eslint/parser": "^8.57.1",
"babel-plugin-react-dev-locator": "^1.0.6",
"baseline-browser-mapping": "^2.10.10",
"eslint": "^10.1.0",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
"typescript-eslint": "^8.57.1"
}
}

View File

@@ -1,10 +0,0 @@
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

245
setup_rdo_schema_final.sql Normal file
View File

@@ -0,0 +1,245 @@
-- ============================================================================
-- SCRIPT DE MIGRAÇÃO: CONFIGURAÇÃO DO ESQUEMA 'rdo'
-- ============================================================================
-- Este script cria o esquema 'rdo', tabelas e permissões necessárias
-- para alinhar o banco de dados com a configuração do app.
-- ============================================================================
-- 1. CRIAR ESQUEMA
-- ============================================================================
CREATE SCHEMA IF NOT EXISTS rdo;
-- 2. GARANTIR EXTENSÕES
-- ============================================================================
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- 3. CRIAR TABELAS NO ESQUEMA 'rdo'
-- ============================================================================
-- Tabela: Organizacoes
CREATE TABLE IF NOT EXISTS rdo.organizacoes (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
nome TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
razao_social TEXT,
cnpj TEXT,
status TEXT DEFAULT 'ativa' CHECK (status IN ('ativa', 'inativa', 'suspensa')),
plano TEXT DEFAULT 'trial' CHECK (plano IN ('trial', 'basico', 'profissional', 'enterprise')),
max_usuarios INTEGER DEFAULT 5,
max_obras INTEGER DEFAULT 10,
max_rdos_mes INTEGER DEFAULT 100,
max_storage_mb INTEGER DEFAULT 1024,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: Usuarios
CREATE TABLE IF NOT EXISTS rdo.usuarios (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
organizacao_id UUID REFERENCES rdo.organizacoes(id) ON DELETE SET NULL,
email TEXT NOT NULL,
nome TEXT NOT NULL,
telefone TEXT,
cargo TEXT,
role TEXT DEFAULT 'usuario' CHECK (role IN ('dev', 'admin', 'engenheiro', 'mestre_obra', 'usuario')),
ativo BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: Obras
CREATE TABLE IF NOT EXISTS rdo.obras (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
organizacao_id UUID NOT NULL REFERENCES rdo.organizacoes(id) ON DELETE CASCADE,
nome TEXT NOT NULL,
descricao TEXT,
endereco TEXT,
cep TEXT,
cidade TEXT,
estado TEXT,
responsavel_id UUID REFERENCES rdo.usuarios(id) ON DELETE SET NULL,
data_inicio DATE,
data_prevista_fim DATE,
data_conclusao DATE,
progresso_geral NUMERIC(5,2) DEFAULT 0,
status TEXT DEFAULT 'ativa' CHECK (status IN ('ativa', 'pausada', 'concluida', 'cancelada')),
configuracoes JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: RDOs
CREATE TABLE IF NOT EXISTS rdo.rdos (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
organizacao_id UUID REFERENCES rdo.organizacoes(id) ON DELETE CASCADE,
obra_id UUID NOT NULL REFERENCES rdo.obras(id) ON DELETE CASCADE,
criado_por UUID NOT NULL REFERENCES rdo.usuarios(id),
data_relatorio DATE NOT NULL,
condicoes_climaticas TEXT NOT NULL,
observacoes_gerais TEXT,
status TEXT DEFAULT 'rascunho' CHECK (status IN ('rascunho', 'enviado', 'aprovado', 'rejeitado')),
aprovado_por UUID REFERENCES rdo.usuarios(id),
aprovado_em TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: RDO Atividades
CREATE TABLE IF NOT EXISTS rdo.rdo_atividades (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE,
tipo_atividade TEXT NOT NULL,
descricao TEXT NOT NULL,
localizacao TEXT,
percentual_concluido NUMERIC(5,2) DEFAULT 0,
ordem INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: RDO Mão de Obra
CREATE TABLE IF NOT EXISTS rdo.rdo_mao_obra (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE,
funcao TEXT NOT NULL,
quantidade INTEGER DEFAULT 0,
horas_trabalhadas NUMERIC(5,2) DEFAULT 0,
observacoes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: RDO Equipamentos
CREATE TABLE IF NOT EXISTS rdo.rdo_equipamentos (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE,
nome_equipamento TEXT NOT NULL,
tipo TEXT,
horas_utilizadas NUMERIC(5,2) DEFAULT 0,
combustivel_gasto NUMERIC(10,2) DEFAULT 0,
observacoes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: RDO Ocorrencias
CREATE TABLE IF NOT EXISTS rdo.rdo_ocorrencias (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE,
tipo_ocorrencia TEXT NOT NULL,
descricao TEXT NOT NULL,
gravidade TEXT CHECK (gravidade IN ('baixa', 'media', 'alta', 'critica')),
acao_tomada TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabela: RDO Anexos
CREATE TABLE IF NOT EXISTS rdo.rdo_anexos (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
rdo_id UUID NOT NULL REFERENCES rdo.rdos(id) ON DELETE CASCADE,
nome_arquivo TEXT NOT NULL,
tipo_arquivo TEXT,
url_storage TEXT NOT NULL,
tamanho_bytes BIGINT,
descricao TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 4. HABILITAR RLS NO NOVO ESQUEMA
-- ============================================================================
ALTER TABLE rdo.organizacoes ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.usuarios ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.obras ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.rdos ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.rdo_atividades ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.rdo_mao_obra ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.rdo_equipamentos ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.rdo_ocorrencias ENABLE ROW LEVEL SECURITY;
ALTER TABLE rdo.rdo_anexos ENABLE ROW LEVEL SECURITY;
-- 5. CRIAR POLÍTICAS PERMISSIVAS (INICIAL) PARA AUTHENTICATED
-- ============================================================================
CREATE POLICY "auth_all_rdo_usuarios" ON rdo.usuarios FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_orgs" ON rdo.organizacoes FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_obras" ON rdo.obras FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_rdos" ON rdo.rdos FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_ativ" ON rdo.rdo_atividades FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_mao" ON rdo.rdo_mao_obra FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_equip" ON rdo.rdo_equipamentos FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_ocor" ON rdo.rdo_ocorrencias FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
CREATE POLICY "auth_all_rdo_anex" ON rdo.rdo_anexos FOR ALL USING (auth.uid() IS NOT NULL) WITH CHECK (auth.uid() IS NOT NULL);
-- 6. PERMISSÕES DE SCHEMA
-- ============================================================================
GRANT USAGE ON SCHEMA rdo TO authenticated, anon;
GRANT ALL ON ALL TABLES IN SCHEMA rdo TO authenticated;
GRANT ALL ON ALL SEQUENCES IN SCHEMA rdo TO authenticated;
GRANT ALL ON ALL FUNCTIONS IN SCHEMA rdo TO authenticated;
-- 7. CORRIGIR TRIGGER PARA O NOVO ESQUEMA
-- ============================================================================
CREATE OR REPLACE FUNCTION rdo.handle_new_user()
RETURNS TRIGGER
SECURITY DEFINER
SET search_path = rdo, public
AS $$
DECLARE
user_name TEXT;
BEGIN
-- Extrair nome
user_name := COALESCE(
NEW.raw_user_meta_data->>'nome',
NEW.raw_user_meta_data->>'name',
NEW.raw_user_meta_data->>'full_name',
split_part(NEW.email, '@', 1)
);
-- Inserir em rdo.usuarios
INSERT INTO rdo.usuarios (
id,
email,
nome,
role,
ativo
) VALUES (
NEW.id,
NEW.email,
user_name,
'usuario',
true
)
ON CONFLICT (id) DO UPDATE SET
email = EXCLUDED.email,
nome = COALESCE(EXCLUDED.nome, rdo.usuarios.nome),
updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Remover trigger antigo se existir em auth.users
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
-- Criar novo trigger apontando para a função no esquema rdo
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION rdo.handle_new_user();
-- 8. DADOS INICIAIS (SEED)
-- ============================================================================
-- Criar organização padrão se não houver nenhuma
INSERT INTO rdo.organizacoes (nome, slug, status, plano)
VALUES ('Baldon Engemetal', 'baldon-engemetal', 'ativa', 'profissional')
ON CONFLICT (slug) DO NOTHING;
-- Garantir que o admin atual seja um usuário no esquema rdo (se ele já existir no Auth)
INSERT INTO rdo.usuarios (id, email, nome, role, ativo)
SELECT id, email, 'Admin TrackSteel', 'dev', true
FROM auth.users
WHERE email = 'admtracksteel@gmail.com'
ON CONFLICT (id) DO UPDATE SET role = 'dev', ativo = true;
-- Associar admin à organização Baldon
UPDATE rdo.usuarios
SET organizacao_id = (SELECT id FROM rdo.organizacoes WHERE slug = 'baldon-engemetal' LIMIT 1)
WHERE email = 'admtracksteel@gmail.com';

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react';
import { useEffect, useState } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { supabase } from '../lib/supabase';
import { queryKeys, invalidateQueries } from '../lib/queryClient';
@@ -7,11 +7,11 @@ import type { RealtimeChannel } from '@supabase/supabase-js';
// Hook para sincronização em tempo real de usuários
export const useUsersRealtime = () => {
const queryClient = useQueryClient();
const channelRef = useRef<RealtimeChannel | null>(null);
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
useEffect(() => {
// Criar canal de subscription
channelRef.current = supabase
const newChannel = supabase
.channel('usuarios-changes')
.on(
'postgres_changes',
@@ -36,24 +36,26 @@ export const useUsersRealtime = () => {
)
.subscribe();
setChannel(newChannel);
// Cleanup na desmontagem
return () => {
if (channelRef.current) {
supabase.removeChannel(channelRef.current);
if (newChannel) {
supabase.removeChannel(newChannel);
}
};
}, [queryClient]);
return channelRef.current;
return channel;
};
// Hook para sincronização em tempo real de obras
export const useObrasRealtimeSync = () => {
const queryClient = useQueryClient();
const channelRef = useRef<RealtimeChannel | null>(null);
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
useEffect(() => {
channelRef.current = supabase
const newChannel = supabase
.channel('obras-changes')
.on(
'postgres_changes',
@@ -81,23 +83,25 @@ export const useObrasRealtimeSync = () => {
)
.subscribe();
setChannel(newChannel);
return () => {
if (channelRef.current) {
supabase.removeChannel(channelRef.current);
if (newChannel) {
supabase.removeChannel(newChannel);
}
};
}, [queryClient]);
return channelRef.current;
return channel;
};
// Hook para sincronização em tempo real de RDOs
export const useRdosRealtimeSync = (obraId?: string) => {
const queryClient = useQueryClient();
const channelRef = useRef<RealtimeChannel | null>(null);
const [channel, setChannel] = useState<RealtimeChannel | null>(null);
useEffect(() => {
channelRef.current = supabase
const newChannel = supabase
.channel('rdos-changes')
.on(
'postgres_changes',
@@ -139,14 +143,16 @@ export const useRdosRealtimeSync = (obraId?: string) => {
)
.subscribe();
setChannel(newChannel);
return () => {
if (channelRef.current) {
supabase.removeChannel(channelRef.current);
if (newChannel) {
supabase.removeChannel(newChannel);
}
};
}, [queryClient, obraId]);
return channelRef.current;
return channel;
};
// Hook principal para sincronização completa

View File

@@ -1,6 +1,21 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@theme {
--breakpoint-xs: 475px;
--max-width-screen-xs: 475px;
--container-padding: 1rem;
--container-center: true;
}
@layer base {
:root {
--container-sm: 1.5rem;
--container-lg: 2rem;
--container-xl: 2.5rem;
--container-2xl: 3rem;
}
}
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;

View File

@@ -103,7 +103,7 @@ export class OfflineManager {
filter?: (item: T) => boolean
): Promise<T[]> {
try {
let query = offlineDb[table].where('_deleted').notEqual(1);
const query = offlineDb[table].where('_deleted').notEqual(1);
const data = await query.toArray();
if (filter) {

View File

@@ -27,7 +27,7 @@ export const SyncLogsPage: React.FC = () => {
setStats(syncStats);
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const handleResolveConflict = (conflictId: string) => {
// Aqui você implementaria a lógica de resolução manual
// Por enquanto, apenas remove o conflito

View File

@@ -159,7 +159,7 @@ export class SyncService {
switch (type) {
case 'INSERT': {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { error: insertError } = await supabase
.from(table)
.insert(data as any);
@@ -173,7 +173,7 @@ export class SyncService {
await this.checkAndResolveConflict(table, data);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { error: updateError } = await supabase
.from(table)
.update(data as any)

View File

@@ -1,32 +0,0 @@
/** @type {import('tailwindcss').Config} */
export default {
darkMode: "class",
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
container: {
center: true,
padding: {
DEFAULT: '1rem',
sm: '1.5rem',
lg: '2rem',
xl: '2.5rem',
'2xl': '3rem',
},
},
screens: {
'xs': '475px',
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
'2xl': '1536px',
},
extend: {
maxWidth: {
'screen-xs': '475px',
},
},
},
plugins: [],
};

View File

@@ -1,66 +1,22 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tsconfigPaths from "vite-tsconfig-paths";
import tailwindcss from '@tailwindcss/vite'
// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
const isDev = command === 'serve';
const isProd = mode === 'production';
return {
export default defineConfig({
// Base path otimizado para Netlify
base: '/',
// Otimizações de build para Netlify
build: {
sourcemap: false, // Desabilitar sourcemaps em produção para reduzir tamanho
target: 'es2020',
minify: 'esbuild',
cssMinify: true,
assetsInlineLimit: 4096, // Inline assets menores que 4KB
minify: true,
emptyOutDir: true,
// Configurações avançadas de chunk splitting
rollupOptions: {
output: {
// Nomes de arquivo com hash para cache busting
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
// Estratégia de splitting otimizada
manualChunks: {
// Vendor chunks para melhor cache
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'query-vendor': ['@tanstack/react-query', '@tanstack/react-query-devtools'],
'supabase-vendor': ['@supabase/supabase-js'],
'ui-vendor': ['lucide-react', 'framer-motion', 'sonner'],
'form-vendor': ['react-hook-form', '@hookform/resolvers', 'zod'],
'state-vendor': ['zustand', 'dexie']
}
}
},
// Configurações de compressão otimizadas para Netlify
reportCompressedSize: false,
chunkSizeWarningLimit: 1000,
// Otimizações específicas para deploy
modulePreload: {
polyfill: false // Reduz o bundle size
}
},
// Otimizações de desenvolvimento
server: {
hmr: {
overlay: false // Reduz ruído visual durante desenvolvimento
},
// Configurações de performance
fs: {
strict: false
}
host: true,
port: 5173,
},
// Configurações de preview otimizadas
@@ -103,18 +59,6 @@ export default defineConfig(({ command, mode }) => {
plugins: [
react(),
tsconfigPaths(),
tailwindcss(),
],
// Configuração para ignorar erros de TypeScript no build
esbuild: {
logOverride: { 'this-is-undefined-in-esm': 'silent' },
...(isProd && {
drop: ['console', 'debugger'],
minifyIdentifiers: true,
minifySyntax: true,
minifyWhitespace: true,
}),
},
};
});