- {t.quote} + {t.texto}+ {t.fotos.length > 0 && ( +
diff --git a/mvp/b2c/drizzle/0006_aspiring_susan_delgado.sql b/mvp/b2c/drizzle/0006_aspiring_susan_delgado.sql
new file mode 100644
index 0000000..377d3ed
--- /dev/null
+++ b/mvp/b2c/drizzle/0006_aspiring_susan_delgado.sql
@@ -0,0 +1,33 @@
+CREATE TYPE "public"."testimonio_estado" AS ENUM('pendiente', 'publicado', 'oculto');--> statement-breakpoint
+CREATE TABLE "testimonio_fotos" (
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
+ "testimonio_id" uuid NOT NULL,
+ "url" text NOT NULL,
+ "orden" integer DEFAULT 0 NOT NULL,
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
+);
+--> statement-breakpoint
+CREATE TABLE "testimonios" (
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
+ "tenant_id" uuid NOT NULL,
+ "lead_id" uuid,
+ "nombre" text NOT NULL,
+ "contexto" text,
+ "rating" integer NOT NULL,
+ "texto" text NOT NULL,
+ "estado" "testimonio_estado" DEFAULT 'pendiente' NOT NULL,
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL
+);
+--> statement-breakpoint
+ALTER TABLE "leads" ADD COLUMN "testimonio_solicitado_at" timestamp with time zone;--> statement-breakpoint
+ALTER TABLE "tenants" ADD COLUMN "seo_title" text;--> statement-breakpoint
+ALTER TABLE "tenants" ADD COLUMN "seo_description" text;--> statement-breakpoint
+ALTER TABLE "tenants" ADD COLUMN "about_enabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint
+ALTER TABLE "tenants" ADD COLUMN "about_foto_url" text;--> statement-breakpoint
+ALTER TABLE "tenants" ADD COLUMN "about_texto" text;--> statement-breakpoint
+ALTER TABLE "tenants" ADD COLUMN "anios_experiencia" integer;--> statement-breakpoint
+ALTER TABLE "testimonio_fotos" ADD CONSTRAINT "testimonio_fotos_testimonio_id_testimonios_id_fk" FOREIGN KEY ("testimonio_id") REFERENCES "public"."testimonios"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "testimonios" ADD CONSTRAINT "testimonios_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "testimonios" ADD CONSTRAINT "testimonios_lead_id_leads_id_fk" FOREIGN KEY ("lead_id") REFERENCES "public"."leads"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
+CREATE INDEX "testimonios_tenant_estado_idx" ON "testimonios" USING btree ("tenant_id","estado");--> statement-breakpoint
+CREATE INDEX "testimonios_lead_idx" ON "testimonios" USING btree ("lead_id");
\ No newline at end of file
diff --git a/mvp/b2c/drizzle/meta/0006_snapshot.json b/mvp/b2c/drizzle/meta/0006_snapshot.json
new file mode 100644
index 0000000..b23694c
--- /dev/null
+++ b/mvp/b2c/drizzle/meta/0006_snapshot.json
@@ -0,0 +1,1488 @@
+{
+ "id": "a8e37a10-3711-4a96-bbd5-3031dcbac788",
+ "prevId": "c521ce73-a6cb-43d8-b3f6-54761e69cea8",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.catalog_items": {
+ "name": "catalog_items",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "categoria": {
+ "name": "categoria",
+ "type": "categoria_material",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "nombre": {
+ "name": "nombre",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "calidad": {
+ "name": "calidad",
+ "type": "calidad",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "precio_unit": {
+ "name": "precio_unit",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "unidad": {
+ "name": "unidad",
+ "type": "unidad_medida",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "descriptor_render": {
+ "name": "descriptor_render",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "''"
+ },
+ "es_default": {
+ "name": "es_default",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "sku": {
+ "name": "sku",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "catalog_tenant_idx": {
+ "name": "catalog_tenant_idx",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "catalog_tenant_sku_idx": {
+ "name": "catalog_tenant_sku_idx",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "sku",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "catalog_items_tenant_id_tenants_id_fk": {
+ "name": "catalog_items_tenant_id_tenants_id_fk",
+ "tableFrom": "catalog_items",
+ "tableTo": "tenants",
+ "columnsFrom": [
+ "tenant_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.lead_estado_history": {
+ "name": "lead_estado_history",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "lead_id": {
+ "name": "lead_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "estado": {
+ "name": "estado",
+ "type": "lead_estado",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "changed_at": {
+ "name": "changed_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "changed_by": {
+ "name": "changed_by",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "lead_estado_history_lead_id_leads_id_fk": {
+ "name": "lead_estado_history_lead_id_leads_id_fk",
+ "tableFrom": "lead_estado_history",
+ "tableTo": "leads",
+ "columnsFrom": [
+ "lead_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.lead_fotos": {
+ "name": "lead_fotos",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "lead_id": {
+ "name": "lead_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "orden": {
+ "name": "orden",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "lead_fotos_lead_id_leads_id_fk": {
+ "name": "lead_fotos_lead_id_leads_id_fk",
+ "tableFrom": "lead_fotos",
+ "tableTo": "leads",
+ "columnsFrom": [
+ "lead_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.lead_pipeline_eventos": {
+ "name": "lead_pipeline_eventos",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "lead_id": {
+ "name": "lead_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "stage": {
+ "name": "stage",
+ "type": "pipeline_stage",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "occurred_at": {
+ "name": "occurred_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "lead_pipeline_eventos_lead_id_leads_id_fk": {
+ "name": "lead_pipeline_eventos_lead_id_leads_id_fk",
+ "tableFrom": "lead_pipeline_eventos",
+ "tableTo": "leads",
+ "columnsFrom": [
+ "lead_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.leads": {
+ "name": "leads",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "nombre": {
+ "name": "nombre",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "telefono": {
+ "name": "telefono",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provincia": {
+ "name": "provincia",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "tipo_reforma": {
+ "name": "tipo_reforma",
+ "type": "tipo_reforma",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_privacidad": {
+ "name": "consent_privacidad",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "consent_contratacion": {
+ "name": "consent_contratacion",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "pipeline_stage": {
+ "name": "pipeline_stage",
+ "type": "pipeline_stage",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'form_completado'"
+ },
+ "estado": {
+ "name": "estado",
+ "type": "lead_estado",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'nuevo'"
+ },
+ "presupuesto_estimado": {
+ "name": "presupuesto_estimado",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "transcripcion": {
+ "name": "transcripcion",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "entidades": {
+ "name": "entidades",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "render_url": {
+ "name": "render_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pdf_url": {
+ "name": "pdf_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "audio_url": {
+ "name": "audio_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notas": {
+ "name": "notas",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "testimonio_solicitado_at": {
+ "name": "testimonio_solicitado_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "m2_suelo": {
+ "name": "m2_suelo",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "altura_techo": {
+ "name": "altura_techo",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "calidad_global": {
+ "name": "calidad_global",
+ "type": "calidad",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estructural": {
+ "name": "estructural",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "material_selections": {
+ "name": "material_selections",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "desglose_snapshot": {
+ "name": "desglose_snapshot",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "urgencia": {
+ "name": "urgencia",
+ "type": "urgencia",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "presupuesto_target": {
+ "name": "presupuesto_target",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "taste_text": {
+ "name": "taste_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "preferences_snapshot": {
+ "name": "preferences_snapshot",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "leads_tenant_created_idx": {
+ "name": "leads_tenant_created_idx",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leads_estado_idx": {
+ "name": "leads_estado_idx",
+ "columns": [
+ {
+ "expression": "estado",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "leads_tenant_id_tenants_id_fk": {
+ "name": "leads_tenant_id_tenants_id_fk",
+ "tableFrom": "leads",
+ "tableTo": "tenants",
+ "columnsFrom": [
+ "tenant_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.plans": {
+ "name": "plans",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "nombre": {
+ "name": "nombre",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "precio_mensual": {
+ "name": "precio_mensual",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "leads_incluidos": {
+ "name": "leads_incluidos",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "features": {
+ "name": "features",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "activo": {
+ "name": "activo",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "plans_slug_unique": {
+ "name": "plans_slug_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "slug"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.precision_history": {
+ "name": "precision_history",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "lead_id": {
+ "name": "lead_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "estimated": {
+ "name": "estimated",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "final": {
+ "name": "final",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "delta_pct": {
+ "name": "delta_pct",
+ "type": "numeric(6, 2)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "precision_history_lead_id_leads_id_fk": {
+ "name": "precision_history_lead_id_leads_id_fk",
+ "tableFrom": "precision_history",
+ "tableTo": "leads",
+ "columnsFrom": [
+ "lead_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.pricing_config": {
+ "name": "pricing_config",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "altura_techo_default": {
+ "name": "altura_techo_default",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 2.5
+ },
+ "factor_zona": {
+ "name": "factor_zona",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "mano_obra": {
+ "name": "mano_obra",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "pricing_config_tenant_id_tenants_id_fk": {
+ "name": "pricing_config_tenant_id_tenants_id_fk",
+ "tableFrom": "pricing_config",
+ "tableTo": "tenants",
+ "columnsFrom": [
+ "tenant_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "pricing_config_tenant_id_unique": {
+ "name": "pricing_config_tenant_id_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "tenant_id"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.sessions": {
+ "name": "sessions",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "sessions_user_idx": {
+ "name": "sessions_user_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "sessions_user_id_users_id_fk": {
+ "name": "sessions_user_id_users_id_fk",
+ "tableFrom": "sessions",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "sessions_token_hash_unique": {
+ "name": "sessions_token_hash_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "token_hash"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.tenants": {
+ "name": "tenants",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "nombre_empresa": {
+ "name": "nombre_empresa",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "logo_url": {
+ "name": "logo_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provincia": {
+ "name": "provincia",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "whatsapp_business": {
+ "name": "whatsapp_business",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "seo_title": {
+ "name": "seo_title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "seo_description": {
+ "name": "seo_description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "about_enabled": {
+ "name": "about_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "about_foto_url": {
+ "name": "about_foto_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "about_texto": {
+ "name": "about_texto",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "anios_experiencia": {
+ "name": "anios_experiencia",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cif": {
+ "name": "cif",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "direccion": {
+ "name": "direccion",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "telefono": {
+ "name": "telefono",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "web": {
+ "name": "web",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "plan_id": {
+ "name": "plan_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "subscription_status": {
+ "name": "subscription_status",
+ "type": "subscription_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'trial'"
+ },
+ "envio_presupuesto": {
+ "name": "envio_presupuesto",
+ "type": "envio_presupuesto_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'automatico'"
+ },
+ "trial_ends_at": {
+ "name": "trial_ends_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "stripe_customer_id": {
+ "name": "stripe_customer_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "tenants_plan_id_plans_id_fk": {
+ "name": "tenants_plan_id_plans_id_fk",
+ "tableFrom": "tenants",
+ "tableTo": "plans",
+ "columnsFrom": [
+ "plan_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "tenants_slug_unique": {
+ "name": "tenants_slug_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "slug"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.testimonio_fotos": {
+ "name": "testimonio_fotos",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "testimonio_id": {
+ "name": "testimonio_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "orden": {
+ "name": "orden",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "testimonio_fotos_testimonio_id_testimonios_id_fk": {
+ "name": "testimonio_fotos_testimonio_id_testimonios_id_fk",
+ "tableFrom": "testimonio_fotos",
+ "tableTo": "testimonios",
+ "columnsFrom": [
+ "testimonio_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.testimonios": {
+ "name": "testimonios",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "lead_id": {
+ "name": "lead_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "nombre": {
+ "name": "nombre",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "contexto": {
+ "name": "contexto",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "rating": {
+ "name": "rating",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "texto": {
+ "name": "texto",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "estado": {
+ "name": "estado",
+ "type": "testimonio_estado",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'pendiente'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "testimonios_tenant_estado_idx": {
+ "name": "testimonios_tenant_estado_idx",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "estado",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "testimonios_lead_idx": {
+ "name": "testimonios_lead_idx",
+ "columns": [
+ {
+ "expression": "lead_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "testimonios_tenant_id_tenants_id_fk": {
+ "name": "testimonios_tenant_id_tenants_id_fk",
+ "tableFrom": "testimonios",
+ "tableTo": "tenants",
+ "columnsFrom": [
+ "tenant_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "testimonios_lead_id_leads_id_fk": {
+ "name": "testimonios_lead_id_leads_id_fk",
+ "tableFrom": "testimonios",
+ "tableTo": "leads",
+ "columnsFrom": [
+ "lead_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "nombre": {
+ "name": "nombre",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "role": {
+ "name": "role",
+ "type": "user_role",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'reformista'"
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "user_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'activo'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "users_tenant_idx": {
+ "name": "users_tenant_idx",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "users_tenant_id_tenants_id_fk": {
+ "name": "users_tenant_id_tenants_id_fk",
+ "tableFrom": "users",
+ "tableTo": "tenants",
+ "columnsFrom": [
+ "tenant_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "users_email_unique": {
+ "name": "users_email_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "email"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.calidad": {
+ "name": "calidad",
+ "schema": "public",
+ "values": [
+ "basica",
+ "media",
+ "premium"
+ ]
+ },
+ "public.categoria_material": {
+ "name": "categoria_material",
+ "schema": "public",
+ "values": [
+ "suelo",
+ "pared",
+ "pintura",
+ "mobiliario"
+ ]
+ },
+ "public.envio_presupuesto_mode": {
+ "name": "envio_presupuesto_mode",
+ "schema": "public",
+ "values": [
+ "automatico",
+ "revision"
+ ]
+ },
+ "public.lead_estado": {
+ "name": "lead_estado",
+ "schema": "public",
+ "values": [
+ "nuevo",
+ "contactado",
+ "visita_agendada",
+ "presupuesto_enviado",
+ "ganado",
+ "perdido"
+ ]
+ },
+ "public.pipeline_stage": {
+ "name": "pipeline_stage",
+ "schema": "public",
+ "values": [
+ "form_completado",
+ "fotos_subidas",
+ "prellamada_enviada",
+ "llamada_completada",
+ "render_generado",
+ "presupuesto_generado",
+ "whatsapp_entregado"
+ ]
+ },
+ "public.subscription_status": {
+ "name": "subscription_status",
+ "schema": "public",
+ "values": [
+ "trial",
+ "activo",
+ "cancelado",
+ "vencido"
+ ]
+ },
+ "public.testimonio_estado": {
+ "name": "testimonio_estado",
+ "schema": "public",
+ "values": [
+ "pendiente",
+ "publicado",
+ "oculto"
+ ]
+ },
+ "public.tipo_reforma": {
+ "name": "tipo_reforma",
+ "schema": "public",
+ "values": [
+ "cocina",
+ "bano",
+ "salon",
+ "comedor",
+ "integral",
+ "otro"
+ ]
+ },
+ "public.unidad_medida": {
+ "name": "unidad_medida",
+ "schema": "public",
+ "values": [
+ "m2",
+ "ml",
+ "ud"
+ ]
+ },
+ "public.urgencia": {
+ "name": "urgencia",
+ "schema": "public",
+ "values": [
+ "alta",
+ "media",
+ "baja"
+ ]
+ },
+ "public.user_role": {
+ "name": "user_role",
+ "schema": "public",
+ "values": [
+ "reformista",
+ "admin"
+ ]
+ },
+ "public.user_status": {
+ "name": "user_status",
+ "schema": "public",
+ "values": [
+ "activo",
+ "deshabilitado"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/mvp/b2c/drizzle/meta/_journal.json b/mvp/b2c/drizzle/meta/_journal.json
index 041c1e8..0ce359e 100644
--- a/mvp/b2c/drizzle/meta/_journal.json
+++ b/mvp/b2c/drizzle/meta/_journal.json
@@ -43,6 +43,13 @@
"when": 1780237037524,
"tag": "0005_tearful_maverick",
"breakpoints": true
+ },
+ {
+ "idx": 6,
+ "version": "7",
+ "when": 1780308810691,
+ "tag": "0006_aspiring_susan_delgado",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/mvp/b2c/src/app/[slug]/page.tsx b/mvp/b2c/src/app/[slug]/page.tsx
index 0bd8ef3..ff20356 100644
--- a/mvp/b2c/src/app/[slug]/page.tsx
+++ b/mvp/b2c/src/app/[slug]/page.tsx
@@ -3,10 +3,11 @@ import { notFound } from 'next/navigation';
import Hero from '@/components/Hero/Hero';
import ReformaSlider from '@/components/ReformaSlider/ReformaSlider';
import Features from '@/components/Features/Features';
-import Testimonials from '@/components/Testimonials/Testimonials';
+import QuienesSomos from '@/components/funnel/QuienesSomos';
+import TestimoniosCliente from '@/components/funnel/TestimoniosCliente';
import Footer from '@/components/Footer/Footer';
import TenantBrand from '@/components/funnel/TenantBrand';
-import { getTenantBySlug } from '@/lib/funnel/public-queries';
+import { getTenantBySlug, getPublishedTestimonios } from '@/lib/funnel/public-queries';
export const dynamic = 'force-dynamic';
@@ -19,8 +20,10 @@ export async function generateMetadata({
const tenant = await getTenantBySlug(slug);
if (!tenant) return { title: 'Reforma no encontrada' };
return {
- title: `${tenant.nombreEmpresa} · Presupuesto de reforma`,
- description: `Pide tu presupuesto de reforma a ${tenant.nombreEmpresa}. Render IA y presupuesto orientativo en minutos.`,
+ title: tenant.seoTitle ?? `${tenant.nombreEmpresa} · Presupuesto de reforma`,
+ description:
+ tenant.seoDescription ??
+ `Pide tu presupuesto de reforma a ${tenant.nombreEmpresa}. Render IA y presupuesto orientativo en minutos.`,
};
}
@@ -29,6 +32,8 @@ export default async function FunnelPage({ params }: { params: Promise<{ slug: s
const tenant = await getTenantBySlug(slug);
if (!tenant) notFound();
+ const testimonios = await getPublishedTestimonios(tenant.id);
+
return (
<>
+ Tu opinión nos ayuda muchísimo. Cuéntanos cómo fue y, si quieres, sube alguna foto del + resultado. +
+¡Gracias por tomarte el tiempo!
++ Solicitada el {formatFecha(lead.testimonioSolicitadoAt)}. Comparte este enlace con el + cliente para que deje su opinión. Cuando la envíe, la verás en{' '} + + Opiniones + {' '} + para aprobarla. +
++ Si la reforma ha ido bien, pídele su opinión. Generamos un enlace para que valore y + suba fotos del resultado. +
+ ++ Disponible cuando marques este lead como ganado. +
+ )} ++ Personaliza cómo aparece tu página en Google y al compartirla. Si lo dejas vacío, + usamos un texto por defecto con el nombre de tu empresa. +
++ Si lo activas, en tu funnel aparece un bloque con tu foto, tu historia y tus años de + experiencia. +
++ Tu foto o la de tu equipo. Aparece en el bloque “Quiénes somos” de tu funnel. +
++ Las opiniones que te dejan tus clientes. Aprueba las que quieras mostrar en tu funnel; solo + las publicadas aparecen en tu página. +
+{t.texto}
+ + {t.fotos.length > 0 && ( ++ La hemos recibido correctamente. Aparecerá en la web del reformista una vez la revise. +
+{texto}
+- Mismo método, distintos espacios. Sin filtros ni guion. -
- {t.quote} + {t.texto}+ {t.fotos.length > 0 && ( +
{state.error}
} + {state?.ok &&Foto actualizada ✓
} +PNG, JPG o WEBP · máx. 1,5 MB.
+