refactor: update packages to React 19, Vite 8 and Tailwind 4 and modernize configs
This commit is contained in:
1
dist/assets/js/form-vendor-vQotxSmE.js
vendored
1
dist/assets/js/form-vendor-vQotxSmE.js
vendored
File diff suppressed because one or more lines are too long
32
dist/assets/js/react-vendor-CqRd3GwO.js
vendored
32
dist/assets/js/react-vendor-CqRd3GwO.js
vendored
File diff suppressed because one or more lines are too long
12
dist/assets/js/router-vendor-D4by-_6Z.js
vendored
12
dist/assets/js/router-vendor-D4by-_6Z.js
vendored
File diff suppressed because one or more lines are too long
1
dist/assets/js/zod-7IfHMaWP.js
vendored
1
dist/assets/js/zod-7IfHMaWP.js
vendored
@@ -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};
|
||||
1
dist/assets/png/tracksteel-logo-CJR9ckUT.png
vendored
1
dist/assets/png/tracksteel-logo-CJR9ckUT.png
vendored
File diff suppressed because one or more lines are too long
18
dist/index.html
vendored
18
dist/index.html
vendored
@@ -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>
|
||||
|
||||
4902
package-lock.json
generated
4902
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
83
package.json
83
package.json
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
245
setup_rdo_schema_final.sql
Normal 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';
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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: [],
|
||||
};
|
||||
@@ -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,
|
||||
}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user