fix: crash bugs in TeamInvoices + faster load
Bug fixes: - TeamInvoices: add useAuth import/currentUser (invoice-create crash) - TeamInvoices: setChartYear -> setExportYear (year-dropdown crash) - TeamDashboard: drop redundant setState-in-effect (cascading renders) - Companies: delete dead _UnusedClientCompanies (illegal hook calls) - annotate intentional empty PDF-fallback catches Load speed: - preconnect/dns-prefetch to Supabase origin - lazy-load heic-to in Converters: page chunk 2737KB -> 9KB - split recharts into its own 'charts' vendor chunk Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
create or replace function public.get_my_role()
|
||||
returns text as $$
|
||||
select role from public.profiles where id = auth.uid();
|
||||
$$ language sql security definer stable
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.is_external()
|
||||
returns boolean as $$
|
||||
select get_my_role() = 'external';
|
||||
$$ language sql security definer stable
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.get_my_company_id()
|
||||
returns uuid as $$
|
||||
select company_id from public.profiles where id = auth.uid();
|
||||
$$ language sql security definer stable
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.has_company_access(company uuid)
|
||||
returns boolean as $$
|
||||
select exists (
|
||||
select 1
|
||||
from public.profiles p
|
||||
where p.id = auth.uid()
|
||||
and (
|
||||
p.company_id = company
|
||||
or exists (
|
||||
select 1
|
||||
from public.company_members cm
|
||||
where cm.profile_id = auth.uid()
|
||||
and cm.company_id = company
|
||||
)
|
||||
)
|
||||
);
|
||||
$$ language sql security definer stable
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.guard_task_update()
|
||||
returns trigger as $$
|
||||
declare
|
||||
caller_role text;
|
||||
begin
|
||||
select role into caller_role from public.profiles where id = auth.uid();
|
||||
|
||||
if caller_role = 'client' then
|
||||
new.project_id := old.project_id;
|
||||
new.invoiced := old.invoiced;
|
||||
|
||||
if not (
|
||||
new.status = 'not_started'
|
||||
and coalesce(new.current_version, 0) > coalesce(old.current_version, 0)
|
||||
and new.assigned_to is null
|
||||
and new.assigned_name is null
|
||||
) then
|
||||
new.assigned_to := old.assigned_to;
|
||||
new.assigned_name := old.assigned_name;
|
||||
end if;
|
||||
elsif caller_role = 'external' then
|
||||
new.project_id := old.project_id;
|
||||
new.invoiced := old.invoiced;
|
||||
end if;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.handle_new_user()
|
||||
returns trigger as $$
|
||||
begin
|
||||
insert into public.profiles (id, name, email, role)
|
||||
values (
|
||||
new.id,
|
||||
coalesce(new.raw_user_meta_data->>'name', ''),
|
||||
new.email,
|
||||
coalesce(new.raw_user_meta_data->>'role', 'client')
|
||||
);
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.prevent_duplicate_active_subcontractor_po_task()
|
||||
returns trigger as $$
|
||||
declare
|
||||
current_po_status text;
|
||||
duplicate_po_number text;
|
||||
begin
|
||||
if new.task_id is null then
|
||||
return new;
|
||||
end if;
|
||||
|
||||
select status into current_po_status
|
||||
from public.subcontractor_payments
|
||||
where id = new.po_id;
|
||||
|
||||
if current_po_status = 'cancelled' then
|
||||
return new;
|
||||
end if;
|
||||
|
||||
select sp.po_number into duplicate_po_number
|
||||
from public.subcontractor_po_items item
|
||||
join public.subcontractor_payments sp on sp.id = item.po_id
|
||||
where item.task_id = new.task_id
|
||||
and item.id <> coalesce(new.id, '00000000-0000-0000-0000-000000000000'::uuid)
|
||||
and sp.status <> 'cancelled'
|
||||
limit 1;
|
||||
|
||||
if duplicate_po_number is not null then
|
||||
raise exception 'Task is already attached to active subcontractor PO %', duplicate_po_number
|
||||
using errcode = '23505';
|
||||
end if;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.prevent_duplicate_on_subcontractor_po_reactivation()
|
||||
returns trigger as $$
|
||||
declare
|
||||
duplicate_task_title text;
|
||||
begin
|
||||
if old.status = new.status or new.status = 'cancelled' then
|
||||
return new;
|
||||
end if;
|
||||
|
||||
select t.title into duplicate_task_title
|
||||
from public.subcontractor_po_items current_item
|
||||
join public.subcontractor_po_items other_item
|
||||
on other_item.task_id = current_item.task_id
|
||||
and other_item.po_id <> current_item.po_id
|
||||
join public.subcontractor_payments other_po
|
||||
on other_po.id = other_item.po_id
|
||||
and other_po.status <> 'cancelled'
|
||||
left join public.tasks t on t.id = current_item.task_id
|
||||
where current_item.po_id = new.id
|
||||
and current_item.task_id is not null
|
||||
limit 1;
|
||||
|
||||
if duplicate_task_title is not null then
|
||||
raise exception 'Cannot reactivate PO because task "%" is already attached to another active subcontractor PO', duplicate_task_title
|
||||
using errcode = '23505';
|
||||
end if;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.sync_subcontractor_project_member()
|
||||
returns trigger as $$
|
||||
begin
|
||||
if new.profile_id is not null and new.project_id is not null then
|
||||
insert into public.project_members (project_id, profile_id)
|
||||
values (new.project_id, new.profile_id)
|
||||
on conflict (project_id, profile_id) do nothing;
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer
|
||||
set search_path = public;
|
||||
|
||||
create or replace function public.sync_project_member_on_task_assign()
|
||||
returns trigger as $$
|
||||
begin
|
||||
if new.assigned_to is not null and new.project_id is not null then
|
||||
insert into public.project_members (project_id, profile_id)
|
||||
values (new.project_id, new.assigned_to)
|
||||
on conflict (project_id, profile_id) do nothing;
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer
|
||||
set search_path = public;
|
||||
|
||||
do $$
|
||||
declare
|
||||
fn record;
|
||||
begin
|
||||
for fn in
|
||||
select n.nspname as schema_name, p.proname as function_name, pg_get_function_identity_arguments(p.oid) as identity_args
|
||||
from pg_proc p
|
||||
join pg_namespace n on n.oid = p.pronamespace
|
||||
where n.nspname = 'public'
|
||||
and p.proname in (
|
||||
'notify_company_folder_sync',
|
||||
'notify_profile_folder_sync',
|
||||
'sync_project_status'
|
||||
)
|
||||
loop
|
||||
execute format(
|
||||
'drop function if exists %I.%I(%s) cascade;',
|
||||
fn.schema_name,
|
||||
fn.function_name,
|
||||
fn.identity_args
|
||||
);
|
||||
end loop;
|
||||
end
|
||||
$$;
|
||||
Reference in New Issue
Block a user