Compare commits
No commits in common. "develop" and "main" have entirely different histories.
5
.env
5
.env
@ -1,5 +0,0 @@
|
||||
SUPABASE_URL="https://qsssikzgwomudkwfmgad.supabase.co"
|
||||
# DATABASE_URL="postgresql://postgres.qsssikzgwomudkwfmgad:etrTXNz3ZOwaLJmT@aws-0-eu-north-1.pooler.supabase.com:6543/postgres"
|
||||
DATABASE_URL="postgresql://postgres.qsssikzgwomudkwfmgad:Wrongly1-Untimed0-Peculiar0-Unlikable7-Cubbyhole8@aws-0-eu-north-1.pooler.supabase.com:6543/postgres"
|
||||
APIKEY_MAPS="AIzaSyAwfOShBqkBcS46WqmlsIVWQJ8gpdOPk_4"
|
||||
SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFzc3Npa3pnd29tdWRrd2ZtZ2FkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQzMjY1NTQsImV4cCI6MjA2OTkwMjU1NH0.BTSscdTcPP1GVmMB-H5caLpWsfuAw1V6mXiqogF8TjU"
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,10 +1 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
count.txt
|
||||
.nitro
|
||||
.tanstack
|
||||
.output
|
||||
.vinxi
|
||||
35
.vscode/settings.json
vendored
35
.vscode/settings.json
vendored
@ -1,35 +0,0 @@
|
||||
{
|
||||
"files.watcherExclude": {
|
||||
"**/routeTree.gen.ts": true
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/routeTree.gen.ts": true
|
||||
},
|
||||
"files.readonlyInclude": {
|
||||
"**/routeTree.gen.ts": true
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "always"
|
||||
}
|
||||
}
|
||||
12
biome.json
12
biome.json
@ -1,19 +1,18 @@
|
||||
{
|
||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.1.3/schema.json",
|
||||
"vcs": {
|
||||
"enabled": false,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": false
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"ignoreUnknown": false,
|
||||
"includes": [
|
||||
"**/src/**/*",
|
||||
"**/.vscode/**/*",
|
||||
"**/index.html",
|
||||
"**/vite.config.js",
|
||||
"!**/src/routeTree.gen.ts",
|
||||
"!**/node_modules/**/*"
|
||||
"!**/src/routeTree.gen.ts"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
@ -27,11 +26,6 @@
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"parser": {
|
||||
"tailwindDirectives": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double",
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import { defineConfig } from 'drizzle-kit'
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/integrations/drizzle/db/schema.ts',
|
||||
out: './src/integrations/supabase/migrations',
|
||||
dialect: 'postgresql',
|
||||
dbCredentials: {
|
||||
url: process.env.DATABASE_URL!
|
||||
},
|
||||
});
|
||||
11629
package-lock.json
generated
11629
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
50
package.json
50
package.json
@ -12,39 +12,29 @@
|
||||
"check": "biome check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroui/react": "^2.8.5",
|
||||
"@supabase/ssr": "^0.8.0",
|
||||
"@supabase/supabase-js": "^2.86.0",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tanstack/react-query": "^5.90.11",
|
||||
"@tanstack/react-query-devtools": "^5.91.1",
|
||||
"@tanstack/react-router": "^1.139.7",
|
||||
"@tanstack/react-router-devtools": "^1.139.7",
|
||||
"@tanstack/react-router-with-query": "^1.130.17",
|
||||
"@tanstack/react-start": "^1.139.8",
|
||||
"@tanstack/router-plugin": "^1.139.7",
|
||||
"@vis.gl/react-google-maps": "^1.7.1",
|
||||
"drizzle-orm": "^0.44.7",
|
||||
"@heroui/react": "^2.8.2",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"@tanstack/react-query": "^5.84.1",
|
||||
"@tanstack/react-query-devtools": "^5.84.1",
|
||||
"@tanstack/react-router": "^1.130.12",
|
||||
"@tanstack/react-router-devtools": "^1.130.13",
|
||||
"@tanstack/react-router-with-query": "^1.130.12",
|
||||
"@tanstack/react-start": "^1.130.15",
|
||||
"@tanstack/router-plugin": "^1.130.15",
|
||||
"framer-motion": "^12.23.12",
|
||||
"postgres": "^3.4.7",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"sonner": "^2.0.7",
|
||||
"zod": "^4.1.13"
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.8",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"@tanstack/react-router-ssr-query": "^1.139.7",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"@types/google.maps": "^3.58.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"drizzle-kit": "^0.31.7",
|
||||
"jsdom": "^27.2.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.2.4",
|
||||
"@biomejs/biome": "2.1.3",
|
||||
"@types/react": "^19.1.9",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@vitejs/plugin-react": "^4.7.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^6.3.5",
|
||||
"web-vitals": "^5.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 402 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB |
@ -1,4 +0,0 @@
|
||||
## Supabase
|
||||
Usuarios de prueba demo12 - juan.penalver@outlook.com
|
||||
|
||||
test
|
||||
@ -1,133 +0,0 @@
|
||||
import { sql } from "drizzle-orm"
|
||||
import {
|
||||
boolean,
|
||||
decimal,
|
||||
integer,
|
||||
pgPolicy,
|
||||
pgTable,
|
||||
serial,
|
||||
text,
|
||||
uuid,
|
||||
varchar
|
||||
} from "drizzle-orm/pg-core"
|
||||
import { authenticatedRole, authUsers } from "drizzle-orm/supabase"
|
||||
|
||||
// === drones ===
|
||||
export const dronesSchema = pgTable("drones", {
|
||||
id: serial("id").primaryKey().notNull(),
|
||||
model: varchar("model", { length: 100 }),
|
||||
brand: varchar("brand", { length: 100 })
|
||||
// type: jsonb("type")
|
||||
}).enableRLS()
|
||||
|
||||
// === certs ===
|
||||
export const certsSchema = pgTable("certs", {
|
||||
id: serial("id").primaryKey().notNull(),
|
||||
name: varchar("name", { length: 100 }),
|
||||
link: text("link")
|
||||
}).enableRLS()
|
||||
|
||||
// === places ===
|
||||
export const placesSchema = pgTable(
|
||||
"places",
|
||||
{
|
||||
id: serial("id").primaryKey().notNull(),
|
||||
coord_x: decimal("coord_x"),
|
||||
coord_y: decimal("coord_y"),
|
||||
description: varchar("description", { length: 255 }),
|
||||
name: varchar("name", { length: 100 }),
|
||||
id_user: uuid("id_user")
|
||||
.notNull()
|
||||
.references(() => authUsers.id, { onDelete: "cascade" }),
|
||||
hidden_place: boolean("hidden_place")
|
||||
},
|
||||
(table) => [
|
||||
pgPolicy("select-own-places", {
|
||||
for: "select",
|
||||
to: authenticatedRole,
|
||||
using: sql`${table.id_user} = auth.uid()`
|
||||
}),
|
||||
pgPolicy("insert-own-places", {
|
||||
for: "insert",
|
||||
to: authenticatedRole,
|
||||
withCheck: sql`${table.id_user} = auth.uid()`
|
||||
}),
|
||||
pgPolicy("update-own-places", {
|
||||
for: "update",
|
||||
to: authenticatedRole,
|
||||
using: sql`${table.id_user} = auth.uid()`,
|
||||
withCheck: sql`${table.id_user} = auth.uid()`
|
||||
})
|
||||
]
|
||||
).enableRLS()
|
||||
|
||||
// === users_drones ===
|
||||
export const usersDronesSchema = pgTable(
|
||||
"users_drones",
|
||||
{
|
||||
id: serial("id").primaryKey().notNull(),
|
||||
id_drone: integer("id_drone").references(() => dronesSchema.id),
|
||||
id_user: uuid("id_user").references(() => authUsers.id)
|
||||
},
|
||||
(table) => [
|
||||
pgPolicy("select-own-user-drones", {
|
||||
for: "select",
|
||||
to: authenticatedRole,
|
||||
using: sql`${table.id_user} = auth.uid()`
|
||||
}),
|
||||
pgPolicy("insert-own-user-drones", {
|
||||
for: "insert",
|
||||
to: authenticatedRole,
|
||||
withCheck: sql`${table.id_user} = auth.uid()`
|
||||
})
|
||||
]
|
||||
).enableRLS()
|
||||
|
||||
// === users_certs ===
|
||||
export const usersCertsSchema = pgTable(
|
||||
"users_certs",
|
||||
{
|
||||
id: serial("id").primaryKey().notNull(),
|
||||
id_cert: integer("id_cert").references(() => certsSchema.id),
|
||||
id_user: uuid("id_user").references(() => authUsers.id)
|
||||
},
|
||||
(table) => [
|
||||
pgPolicy("select-own-user-certs", {
|
||||
for: "select",
|
||||
to: authenticatedRole,
|
||||
using: sql`${table.id_user} = auth.uid()`
|
||||
}),
|
||||
pgPolicy("insert-own-user-certs", {
|
||||
for: "insert",
|
||||
to: authenticatedRole,
|
||||
withCheck: sql`${table.id_user} = auth.uid()`
|
||||
})
|
||||
]
|
||||
).enableRLS()
|
||||
|
||||
// === users_places ===
|
||||
export const usersPlacesSchema = pgTable(
|
||||
"users_places",
|
||||
{
|
||||
id: serial("id").primaryKey().notNull(),
|
||||
id_place: integer("id_place").references(() => placesSchema.id),
|
||||
id_user: uuid("id_user").references(() => authUsers.id)
|
||||
},
|
||||
(table) => [
|
||||
pgPolicy("select-own-user-places", {
|
||||
for: "select",
|
||||
to: authenticatedRole,
|
||||
using: sql`${table.id_user} = auth.uid()`
|
||||
}),
|
||||
pgPolicy("insert-own-user-places", {
|
||||
for: "insert",
|
||||
to: authenticatedRole,
|
||||
withCheck: sql`${table.id_user} = auth.uid()`
|
||||
})
|
||||
]
|
||||
).enableRLS()
|
||||
|
||||
// === equipment ===
|
||||
export const equipmentSchema = pgTable("equipment", {
|
||||
id: serial("id").primaryKey().notNull()
|
||||
}).enableRLS()
|
||||
@ -1,12 +0,0 @@
|
||||
import { createServerOnlyFn } from "@tanstack/react-start"
|
||||
import { drizzle } from "drizzle-orm/postgres-js"
|
||||
import postgres from "postgres"
|
||||
|
||||
export const db = createServerOnlyFn(() => {
|
||||
const connectionString = process.env.DATABASE_URL ?? ""
|
||||
const client = postgres(connectionString, { prepare: false })
|
||||
|
||||
// Disable prefetch as it is not supported for "Transaction" pool mode
|
||||
|
||||
return drizzle(client)
|
||||
})
|
||||
@ -1,5 +1,5 @@
|
||||
import { HeroUIProvider as HeroProvider } from "@heroui/react"
|
||||
|
||||
export const HeroUIProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
return <HeroProvider validationBehavior="native">{children}</HeroProvider>
|
||||
return <HeroProvider>{children}</HeroProvider>
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { Toaster } from "sonner"
|
||||
|
||||
export const SonnerProvider = () => {
|
||||
return (
|
||||
<Toaster
|
||||
position="top-right"
|
||||
duration={3000}
|
||||
closeButton
|
||||
richColors
|
||||
visibleToasts={3}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
CREATE TABLE "certs" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar(100),
|
||||
"link" text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "certs" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE "drones" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"model" varchar(100),
|
||||
"brand" varchar(100),
|
||||
"type" jsonb
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "drones" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE "equipment" (
|
||||
"id" serial PRIMARY KEY NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "equipment" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE "places" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"coord_x" numeric,
|
||||
"coord_y" numeric,
|
||||
"description" varchar(255),
|
||||
"name" varchar(100),
|
||||
"id_user" uuid NOT NULL,
|
||||
"hidden_place" boolean
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "places" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE "users_certs" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"id_cert" integer,
|
||||
"id_user" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "users_certs" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE "users_drones" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"id_drone" integer,
|
||||
"id_user" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "users_drones" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE "users_places" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"id_place" integer,
|
||||
"id_user" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "users_places" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
ALTER TABLE "places" ADD CONSTRAINT "places_id_user_users_id_fk" FOREIGN KEY ("id_user") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "users_certs" ADD CONSTRAINT "users_certs_id_cert_certs_id_fk" FOREIGN KEY ("id_cert") REFERENCES "public"."certs"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "users_certs" ADD CONSTRAINT "users_certs_id_user_users_id_fk" FOREIGN KEY ("id_user") REFERENCES "auth"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "users_drones" ADD CONSTRAINT "users_drones_id_drone_drones_id_fk" FOREIGN KEY ("id_drone") REFERENCES "public"."drones"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "users_drones" ADD CONSTRAINT "users_drones_id_user_users_id_fk" FOREIGN KEY ("id_user") REFERENCES "auth"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "users_places" ADD CONSTRAINT "users_places_id_place_places_id_fk" FOREIGN KEY ("id_place") REFERENCES "public"."places"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "users_places" ADD CONSTRAINT "users_places_id_user_users_id_fk" FOREIGN KEY ("id_user") REFERENCES "auth"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE POLICY "select-own-places" ON "places" AS PERMISSIVE FOR SELECT TO "authenticated" USING ("places"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "insert-own-places" ON "places" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ("places"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "update-own-places" ON "places" AS PERMISSIVE FOR UPDATE TO "authenticated" USING ("places"."id_user" = auth.uid()) WITH CHECK ("places"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "select-own-user-certs" ON "users_certs" AS PERMISSIVE FOR SELECT TO "authenticated" USING ("users_certs"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "insert-own-user-certs" ON "users_certs" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ("users_certs"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "select-own-user-drones" ON "users_drones" AS PERMISSIVE FOR SELECT TO "authenticated" USING ("users_drones"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "insert-own-user-drones" ON "users_drones" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ("users_drones"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "select-own-user-places" ON "users_places" AS PERMISSIVE FOR SELECT TO "authenticated" USING ("users_places"."id_user" = auth.uid());--> statement-breakpoint
|
||||
CREATE POLICY "insert-own-user-places" ON "users_places" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK ("users_places"."id_user" = auth.uid());
|
||||
@ -1,439 +0,0 @@
|
||||
{
|
||||
"id": "595b3231-9696-413e-b55b-5ec61cb86165",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.certs": {
|
||||
"name": "certs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(100)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"link": {
|
||||
"name": "link",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
},
|
||||
"public.drones": {
|
||||
"name": "drones",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"model": {
|
||||
"name": "model",
|
||||
"type": "varchar(100)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"brand": {
|
||||
"name": "brand",
|
||||
"type": "varchar(100)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
},
|
||||
"public.equipment": {
|
||||
"name": "equipment",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
},
|
||||
"public.places": {
|
||||
"name": "places",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"coord_x": {
|
||||
"name": "coord_x",
|
||||
"type": "numeric",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"coord_y": {
|
||||
"name": "coord_y",
|
||||
"type": "numeric",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(100)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"id_user": {
|
||||
"name": "id_user",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"hidden_place": {
|
||||
"name": "hidden_place",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"places_id_user_users_id_fk": {
|
||||
"name": "places_id_user_users_id_fk",
|
||||
"tableFrom": "places",
|
||||
"tableTo": "users",
|
||||
"schemaTo": "auth",
|
||||
"columnsFrom": [
|
||||
"id_user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {
|
||||
"select-own-places": {
|
||||
"name": "select-own-places",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "SELECT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"using": "\"places\".\"id_user\" = auth.uid()"
|
||||
},
|
||||
"insert-own-places": {
|
||||
"name": "insert-own-places",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "INSERT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"withCheck": "\"places\".\"id_user\" = auth.uid()"
|
||||
},
|
||||
"update-own-places": {
|
||||
"name": "update-own-places",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "UPDATE",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"using": "\"places\".\"id_user\" = auth.uid()",
|
||||
"withCheck": "\"places\".\"id_user\" = auth.uid()"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
},
|
||||
"public.users_certs": {
|
||||
"name": "users_certs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"id_cert": {
|
||||
"name": "id_cert",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"id_user": {
|
||||
"name": "id_user",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"users_certs_id_cert_certs_id_fk": {
|
||||
"name": "users_certs_id_cert_certs_id_fk",
|
||||
"tableFrom": "users_certs",
|
||||
"tableTo": "certs",
|
||||
"columnsFrom": [
|
||||
"id_cert"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"users_certs_id_user_users_id_fk": {
|
||||
"name": "users_certs_id_user_users_id_fk",
|
||||
"tableFrom": "users_certs",
|
||||
"tableTo": "users",
|
||||
"schemaTo": "auth",
|
||||
"columnsFrom": [
|
||||
"id_user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {
|
||||
"select-own-user-certs": {
|
||||
"name": "select-own-user-certs",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "SELECT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"using": "\"users_certs\".\"id_user\" = auth.uid()"
|
||||
},
|
||||
"insert-own-user-certs": {
|
||||
"name": "insert-own-user-certs",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "INSERT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"withCheck": "\"users_certs\".\"id_user\" = auth.uid()"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
},
|
||||
"public.users_drones": {
|
||||
"name": "users_drones",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"id_drone": {
|
||||
"name": "id_drone",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"id_user": {
|
||||
"name": "id_user",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"users_drones_id_drone_drones_id_fk": {
|
||||
"name": "users_drones_id_drone_drones_id_fk",
|
||||
"tableFrom": "users_drones",
|
||||
"tableTo": "drones",
|
||||
"columnsFrom": [
|
||||
"id_drone"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"users_drones_id_user_users_id_fk": {
|
||||
"name": "users_drones_id_user_users_id_fk",
|
||||
"tableFrom": "users_drones",
|
||||
"tableTo": "users",
|
||||
"schemaTo": "auth",
|
||||
"columnsFrom": [
|
||||
"id_user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {
|
||||
"select-own-user-drones": {
|
||||
"name": "select-own-user-drones",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "SELECT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"using": "\"users_drones\".\"id_user\" = auth.uid()"
|
||||
},
|
||||
"insert-own-user-drones": {
|
||||
"name": "insert-own-user-drones",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "INSERT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"withCheck": "\"users_drones\".\"id_user\" = auth.uid()"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
},
|
||||
"public.users_places": {
|
||||
"name": "users_places",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"id_place": {
|
||||
"name": "id_place",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"id_user": {
|
||||
"name": "id_user",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"users_places_id_place_places_id_fk": {
|
||||
"name": "users_places_id_place_places_id_fk",
|
||||
"tableFrom": "users_places",
|
||||
"tableTo": "places",
|
||||
"columnsFrom": [
|
||||
"id_place"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"users_places_id_user_users_id_fk": {
|
||||
"name": "users_places_id_user_users_id_fk",
|
||||
"tableFrom": "users_places",
|
||||
"tableTo": "users",
|
||||
"schemaTo": "auth",
|
||||
"columnsFrom": [
|
||||
"id_user"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {
|
||||
"select-own-user-places": {
|
||||
"name": "select-own-user-places",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "SELECT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"using": "\"users_places\".\"id_user\" = auth.uid()"
|
||||
},
|
||||
"insert-own-user-places": {
|
||||
"name": "insert-own-user-places",
|
||||
"as": "PERMISSIVE",
|
||||
"for": "INSERT",
|
||||
"to": [
|
||||
"authenticated"
|
||||
],
|
||||
"withCheck": "\"users_places\".\"id_user\" = auth.uid()"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": true
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1762798763195,
|
||||
"tag": "0002_init",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
import { createServerClient } from "@supabase/ssr"
|
||||
import { getCookies, setCookie } from "@tanstack/react-start/server"
|
||||
|
||||
export function getSupabaseServerClient() {
|
||||
return createServerClient(
|
||||
process.env.SUPABASE_URL as string,
|
||||
process.env.SUPABASE_ANON_KEY as string,
|
||||
{
|
||||
cookies: {
|
||||
getAll() {
|
||||
return Object.entries(getCookies()).map(([name, value]) => ({
|
||||
name,
|
||||
value
|
||||
}))
|
||||
},
|
||||
setAll(cookies) {
|
||||
cookies.forEach((cookie) => {
|
||||
setCookie(cookie.name, cookie.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
import { useState } from "react"
|
||||
import { z } from "zod"
|
||||
|
||||
type FormDataValidation = Record<string, FormDataEntryValue>
|
||||
|
||||
export const useValidation = <T,>({
|
||||
defaultSchema
|
||||
}: {
|
||||
defaultSchema?: z.ZodSchema<T>
|
||||
}) => {
|
||||
const [errors, setErrors] = useState<T>()
|
||||
|
||||
const validate = ({
|
||||
formData,
|
||||
schema
|
||||
}: {
|
||||
formData: FormDataValidation
|
||||
schema?: z.ZodType<T>
|
||||
}) => {
|
||||
const result =
|
||||
schema?.safeParse(formData) ?? defaultSchema?.safeParse(formData)
|
||||
|
||||
if (!result) {
|
||||
throw new Error("No schema provided")
|
||||
}
|
||||
|
||||
if (!result.success) {
|
||||
setErrors(z.flattenError(result.error).fieldErrors as T)
|
||||
return false
|
||||
}
|
||||
|
||||
setErrors(undefined)
|
||||
return true
|
||||
}
|
||||
|
||||
return { errors, validate }
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useNavigate } from "@tanstack/react-router"
|
||||
import { toast } from "sonner"
|
||||
import type z from "zod"
|
||||
import { user } from "@/lib/server/user"
|
||||
import { loginFormSchema } from "@/lib/validation/user"
|
||||
import { useValidation } from "../useValidation"
|
||||
|
||||
type TLoginForm = z.infer<typeof loginFormSchema>
|
||||
|
||||
export const useLogin = () => {
|
||||
const navigate = useNavigate()
|
||||
const { errors, validate } = useValidation({
|
||||
defaultSchema: loginFormSchema
|
||||
})
|
||||
const loginMutation = useMutation({
|
||||
mutationKey: ["login"],
|
||||
mutationFn: async (data: TLoginForm) => {
|
||||
const response = await user.login({ data })
|
||||
if (response.error) {
|
||||
throw new Error(response.message)
|
||||
}
|
||||
},
|
||||
onMutate: () => {
|
||||
toast.loading("Logging in...", { id: "login" })
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success("Login successful! Redirecting to posts..", { id: "login" })
|
||||
navigate({
|
||||
to: "/dashboard"
|
||||
})
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message, { id: "login" })
|
||||
}
|
||||
})
|
||||
|
||||
const validateLogin = (formData: TLoginForm) => {
|
||||
const isValid = validate({
|
||||
formData
|
||||
})
|
||||
|
||||
if (!isValid) {
|
||||
toast.error("Error en el formulario.")
|
||||
return false
|
||||
}
|
||||
|
||||
loginMutation.mutate(formData)
|
||||
}
|
||||
|
||||
return {
|
||||
login: validateLogin,
|
||||
isPending: loginMutation.isPending,
|
||||
errors: errors
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useNavigate } from "@tanstack/react-router"
|
||||
import { toast } from "sonner"
|
||||
import type z from "zod"
|
||||
import { user } from "@/lib/server/user"
|
||||
import { signupFormSchema } from "@/lib/validation/user"
|
||||
import { useValidation } from "../useValidation"
|
||||
|
||||
type TSignupForm = z.infer<typeof signupFormSchema>
|
||||
|
||||
export const useSignup = () => {
|
||||
const navigate = useNavigate()
|
||||
const { validate, errors } = useValidation({
|
||||
defaultSchema: signupFormSchema
|
||||
})
|
||||
const signup = useMutation({
|
||||
mutationKey: ["signup"],
|
||||
mutationFn: async (data: TSignupForm) => user.signup({ data }),
|
||||
onSuccess: () => {
|
||||
toast.success("Signup successful! Redirecting to login...", {
|
||||
id: "signup"
|
||||
})
|
||||
navigate({
|
||||
to: "/login"
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const validateSignup = (formData: TSignupForm) => {
|
||||
const isValid = validate({ formData })
|
||||
if (!isValid) {
|
||||
toast.error("Signup failed. Please check your input.", {
|
||||
id: "signup"
|
||||
})
|
||||
}
|
||||
signup.mutate(formData)
|
||||
}
|
||||
|
||||
return {
|
||||
signup: validateSignup,
|
||||
errors,
|
||||
isPending: signup.isPending
|
||||
}
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
import { createServerFn } from "@tanstack/react-start"
|
||||
import { eq } from "drizzle-orm"
|
||||
import { db } from "@/integrations/drizzle"
|
||||
import { dronesSchema } from "@/integrations/drizzle/db/schema"
|
||||
import {
|
||||
droneValidationSchema,
|
||||
paginatedDronesValidationSchema
|
||||
} from "../validation/drones"
|
||||
|
||||
const insertDrones = createServerFn()
|
||||
.inputValidator(droneValidationSchema)
|
||||
.handler(async ({ data }) => {
|
||||
await db()
|
||||
.insert(dronesSchema)
|
||||
.values({
|
||||
model: data.model,
|
||||
brand: data.brand
|
||||
})
|
||||
.returning()
|
||||
})
|
||||
|
||||
const editDrone = createServerFn()
|
||||
.inputValidator(
|
||||
droneValidationSchema.pick({
|
||||
model: true,
|
||||
brand: true,
|
||||
id: true
|
||||
})
|
||||
)
|
||||
.handler(async ({ data }) => {
|
||||
await db()
|
||||
.update(dronesSchema)
|
||||
.set({
|
||||
model: data.model,
|
||||
brand: data.brand
|
||||
})
|
||||
.where(eq(dronesSchema.id, data.id))
|
||||
})
|
||||
|
||||
const deleteDrones = createServerFn({
|
||||
method: "POST"
|
||||
})
|
||||
.inputValidator(
|
||||
droneValidationSchema.pick({
|
||||
id: true
|
||||
})
|
||||
)
|
||||
.handler(async ({ data }) => {
|
||||
return await db().delete(dronesSchema).where(eq(dronesSchema.id, data.id))
|
||||
})
|
||||
|
||||
const getAllDrones = createServerFn({
|
||||
method: "POST"
|
||||
})
|
||||
.inputValidator(paginatedDronesValidationSchema)
|
||||
.handler(async ({ data }) => {
|
||||
return db()
|
||||
.select()
|
||||
.from(dronesSchema)
|
||||
.limit(data.limit)
|
||||
.offset((data.page - 1) * data.limit)
|
||||
})
|
||||
|
||||
export const serverDrones = {
|
||||
insertDrones,
|
||||
editDrone,
|
||||
getAllDrones,
|
||||
deleteDrones
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
import { createServerFn } from "@tanstack/react-start"
|
||||
import { eq } from "drizzle-orm"
|
||||
import { db } from "@/integrations/drizzle"
|
||||
import { placesSchema } from "@/integrations/drizzle/db/schema"
|
||||
import {
|
||||
paginatedPlacesValidationSchema,
|
||||
placeValidationSchema
|
||||
} from "../validation/places"
|
||||
|
||||
export const insertUserPlace = createServerFn()
|
||||
.inputValidator(placeValidationSchema)
|
||||
.handler(async ({ data }) => {
|
||||
await db().insert(placesSchema).values(data).returning()
|
||||
})
|
||||
|
||||
export const editUserPlace = createServerFn()
|
||||
.inputValidator(
|
||||
placeValidationSchema.pick({
|
||||
hidden_place: true,
|
||||
name: true,
|
||||
description: true,
|
||||
id_user: true
|
||||
})
|
||||
)
|
||||
.handler(async ({ data }) => {
|
||||
await db()
|
||||
.update(placesSchema)
|
||||
.set(data)
|
||||
.where(eq(placesSchema.id_user, data.id_user))
|
||||
})
|
||||
|
||||
export const getUserPlacesById = createServerFn()
|
||||
.inputValidator(paginatedPlacesValidationSchema)
|
||||
.handler(async ({ data }) => {
|
||||
return await db()
|
||||
.select()
|
||||
.from(placesSchema)
|
||||
.where(eq(placesSchema.id_user, data.id_user))
|
||||
.limit(data.limit)
|
||||
.offset((data.page - 1) * data.limit)
|
||||
})
|
||||
|
||||
export const places = {
|
||||
insertUserPlace,
|
||||
editUserPlace,
|
||||
getUserPlacesById
|
||||
}
|
||||
@ -1,142 +0,0 @@
|
||||
import { redirect } from "@tanstack/react-router"
|
||||
import { createServerFn } from "@tanstack/react-start"
|
||||
import { getSupabaseServerClient } from "@/integrations/supabase/supabase"
|
||||
import {
|
||||
loginFormSchema,
|
||||
signupFormSchema,
|
||||
userListParamsSchema
|
||||
} from "../validation/user"
|
||||
|
||||
const login = createServerFn({ method: "POST" })
|
||||
.inputValidator(loginFormSchema)
|
||||
.handler(async ({ data }) => {
|
||||
const supabase = getSupabaseServerClient()
|
||||
|
||||
const login = await supabase.auth.signInWithPassword({
|
||||
email: data.email,
|
||||
password: data.password
|
||||
})
|
||||
|
||||
if (login.error) {
|
||||
return {
|
||||
error: true,
|
||||
message: login.error.message
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error: false
|
||||
}
|
||||
})
|
||||
|
||||
const logout = createServerFn().handler(async () => {
|
||||
const supabase = getSupabaseServerClient()
|
||||
|
||||
const { error } = await supabase.auth.signOut()
|
||||
if (error) {
|
||||
return {
|
||||
error: true,
|
||||
message: error.message
|
||||
}
|
||||
}
|
||||
|
||||
throw redirect({
|
||||
to: "/",
|
||||
viewTransition: true,
|
||||
replace: true
|
||||
})
|
||||
})
|
||||
|
||||
const signup = createServerFn({ method: "POST" })
|
||||
.inputValidator(signupFormSchema)
|
||||
.handler(async ({ data }) => {
|
||||
const supabase = getSupabaseServerClient()
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email: data.email,
|
||||
password: data.password,
|
||||
options: {
|
||||
data: {
|
||||
name: data.name,
|
||||
location: data.location
|
||||
}
|
||||
}
|
||||
})
|
||||
if (error) {
|
||||
return {
|
||||
error: true,
|
||||
message: error.message
|
||||
}
|
||||
}
|
||||
|
||||
throw redirect({
|
||||
href: data.redirectUrl || "/"
|
||||
})
|
||||
})
|
||||
|
||||
const userData = createServerFn().handler(async () => {
|
||||
const supabase = getSupabaseServerClient()
|
||||
const { data, error } = await supabase.auth.getUser()
|
||||
if (error || !data.user) {
|
||||
return {
|
||||
error: true,
|
||||
message: error?.message ?? "Unknown error"
|
||||
}
|
||||
}
|
||||
return {
|
||||
user: {
|
||||
id: data.user.id,
|
||||
email: data.user.email,
|
||||
name: data.user.user_metadata.name || "",
|
||||
location: data.user.user_metadata.location || ""
|
||||
},
|
||||
error: false
|
||||
}
|
||||
})
|
||||
|
||||
const resendConfirmationEmail = createServerFn({ method: "POST" })
|
||||
.inputValidator(signupFormSchema.pick({ email: true }))
|
||||
.handler(async ({ data }) => {
|
||||
const supabase = getSupabaseServerClient()
|
||||
const { error } = await supabase.auth.resetPasswordForEmail(data.email)
|
||||
|
||||
if (error) {
|
||||
return {
|
||||
error: true,
|
||||
message: error.message
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error: false
|
||||
}
|
||||
})
|
||||
|
||||
const userList = createServerFn()
|
||||
.inputValidator(userListParamsSchema)
|
||||
.handler(async ({ data }) => {
|
||||
const supabase = getSupabaseServerClient()
|
||||
const users = await supabase.auth.admin.listUsers({
|
||||
page: data.page,
|
||||
perPage: data.limit
|
||||
})
|
||||
|
||||
if (users.error) {
|
||||
return {
|
||||
error: true,
|
||||
message: users.error.message
|
||||
}
|
||||
}
|
||||
return {
|
||||
users: users.data,
|
||||
error: false
|
||||
}
|
||||
})
|
||||
|
||||
export const user = {
|
||||
login,
|
||||
logout,
|
||||
signup,
|
||||
userData,
|
||||
resendConfirmationEmail,
|
||||
userList
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
import * as z from "zod"
|
||||
|
||||
export const droneValidationSchema = z.object({
|
||||
model: z.string(),
|
||||
brand: z.string(),
|
||||
id: z.number()
|
||||
})
|
||||
|
||||
export const paginatedDronesValidationSchema = z.object({
|
||||
page: z.number().min(1).default(1),
|
||||
limit: z.number().min(1).max(100).default(10)
|
||||
})
|
||||
@ -1,16 +0,0 @@
|
||||
import * as z from "zod"
|
||||
|
||||
export const placeValidationSchema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
coord_x: z.string(),
|
||||
coord_y: z.string(),
|
||||
id_user: z.string(),
|
||||
hidden_place: z.boolean()
|
||||
})
|
||||
|
||||
export const paginatedPlacesValidationSchema = z.object({
|
||||
page: z.number(),
|
||||
limit: z.number(),
|
||||
id_user: z.string()
|
||||
})
|
||||
@ -1,25 +0,0 @@
|
||||
import * as z from "zod"
|
||||
|
||||
export const loginFormSchema = z.object({
|
||||
email: z.email("Invalid email address"),
|
||||
password: z.string().min(1, "Password must be at least 1 character long")
|
||||
})
|
||||
|
||||
export const signupFormSchema = z.object({
|
||||
email: z.email("Invalid email address"),
|
||||
password: z.string().min(6, "Password must be at least 6 characters long"),
|
||||
name: z.string().min(1, "The field is required"),
|
||||
location: z.string().min(1, "The field is required"),
|
||||
redirectUrl: z.string().optional()
|
||||
})
|
||||
|
||||
export const profileFormSchema = z.object({
|
||||
id: z.uuid(),
|
||||
firstName: z.string().min(1, "First name is required"),
|
||||
lastName: z.string().min(1, "Last name is required")
|
||||
})
|
||||
|
||||
export const userListParamsSchema = z.object({
|
||||
page: z.number().min(1).default(1),
|
||||
limit: z.number().min(1).max(100).default(10)
|
||||
})
|
||||
@ -9,137 +9,38 @@
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as SignupRouteImport } from './routes/signup'
|
||||
import { Route as PlacesRouteImport } from './routes/places'
|
||||
import { Route as LogoutRouteImport } from './routes/logout'
|
||||
import { Route as LoginRouteImport } from './routes/login'
|
||||
import { Route as AuthedRouteImport } from './routes/_authed'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
import { Route as AuthedDashboardRouteImport } from './routes/_authed/dashboard'
|
||||
|
||||
const SignupRoute = SignupRouteImport.update({
|
||||
id: '/signup',
|
||||
path: '/signup',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const PlacesRoute = PlacesRouteImport.update({
|
||||
id: '/places',
|
||||
path: '/places',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const LogoutRoute = LogoutRouteImport.update({
|
||||
id: '/logout',
|
||||
path: '/logout',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const LoginRoute = LoginRouteImport.update({
|
||||
id: '/login',
|
||||
path: '/login',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const AuthedRoute = AuthedRouteImport.update({
|
||||
id: '/_authed',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const IndexRoute = IndexRouteImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const AuthedDashboardRoute = AuthedDashboardRouteImport.update({
|
||||
id: '/dashboard',
|
||||
path: '/dashboard',
|
||||
getParentRoute: () => AuthedRoute,
|
||||
} as any)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/logout': typeof LogoutRoute
|
||||
'/places': typeof PlacesRoute
|
||||
'/signup': typeof SignupRoute
|
||||
'/dashboard': typeof AuthedDashboardRoute
|
||||
}
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/logout': typeof LogoutRoute
|
||||
'/places': typeof PlacesRoute
|
||||
'/signup': typeof SignupRoute
|
||||
'/dashboard': typeof AuthedDashboardRoute
|
||||
}
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/': typeof IndexRoute
|
||||
'/_authed': typeof AuthedRouteWithChildren
|
||||
'/login': typeof LoginRoute
|
||||
'/logout': typeof LogoutRoute
|
||||
'/places': typeof PlacesRoute
|
||||
'/signup': typeof SignupRoute
|
||||
'/_authed/dashboard': typeof AuthedDashboardRoute
|
||||
}
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths: '/' | '/login' | '/logout' | '/places' | '/signup' | '/dashboard'
|
||||
fullPaths: '/'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/' | '/login' | '/logout' | '/places' | '/signup' | '/dashboard'
|
||||
id:
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/_authed'
|
||||
| '/login'
|
||||
| '/logout'
|
||||
| '/places'
|
||||
| '/signup'
|
||||
| '/_authed/dashboard'
|
||||
to: '/'
|
||||
id: '__root__' | '/'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
AuthedRoute: typeof AuthedRouteWithChildren
|
||||
LoginRoute: typeof LoginRoute
|
||||
LogoutRoute: typeof LogoutRoute
|
||||
PlacesRoute: typeof PlacesRoute
|
||||
SignupRoute: typeof SignupRoute
|
||||
}
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/signup': {
|
||||
id: '/signup'
|
||||
path: '/signup'
|
||||
fullPath: '/signup'
|
||||
preLoaderRoute: typeof SignupRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/places': {
|
||||
id: '/places'
|
||||
path: '/places'
|
||||
fullPath: '/places'
|
||||
preLoaderRoute: typeof PlacesRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/logout': {
|
||||
id: '/logout'
|
||||
path: '/logout'
|
||||
fullPath: '/logout'
|
||||
preLoaderRoute: typeof LogoutRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/login': {
|
||||
id: '/login'
|
||||
path: '/login'
|
||||
fullPath: '/login'
|
||||
preLoaderRoute: typeof LoginRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/_authed': {
|
||||
id: '/_authed'
|
||||
path: ''
|
||||
fullPath: ''
|
||||
preLoaderRoute: typeof AuthedRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/': {
|
||||
id: '/'
|
||||
path: '/'
|
||||
@ -147,44 +48,12 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof IndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/_authed/dashboard': {
|
||||
id: '/_authed/dashboard'
|
||||
path: '/dashboard'
|
||||
fullPath: '/dashboard'
|
||||
preLoaderRoute: typeof AuthedDashboardRouteImport
|
||||
parentRoute: typeof AuthedRoute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface AuthedRouteChildren {
|
||||
AuthedDashboardRoute: typeof AuthedDashboardRoute
|
||||
}
|
||||
|
||||
const AuthedRouteChildren: AuthedRouteChildren = {
|
||||
AuthedDashboardRoute: AuthedDashboardRoute,
|
||||
}
|
||||
|
||||
const AuthedRouteWithChildren =
|
||||
AuthedRoute._addFileChildren(AuthedRouteChildren)
|
||||
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
AuthedRoute: AuthedRouteWithChildren,
|
||||
LoginRoute: LoginRoute,
|
||||
LogoutRoute: LogoutRoute,
|
||||
PlacesRoute: PlacesRoute,
|
||||
SignupRoute: SignupRoute,
|
||||
}
|
||||
export const routeTree = rootRouteImport
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
import type { getRouter } from './router.tsx'
|
||||
import type { createStart } from '@tanstack/react-start'
|
||||
declare module '@tanstack/react-start' {
|
||||
interface Register {
|
||||
ssr: true
|
||||
router: Awaited<ReturnType<typeof getRouter>>
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,35 +1,27 @@
|
||||
import { createRouter } from "@tanstack/react-router"
|
||||
import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"
|
||||
import { createRouter as createTanstackRouter } from "@tanstack/react-router"
|
||||
import { routerWithQueryClient } from "@tanstack/react-router-with-query"
|
||||
import { createQueryContext } from "./integrations/tanstack-query/context.tsx"
|
||||
import { QueryProvider } from "./integrations/tanstack-query/provider.tsx"
|
||||
import { routeTree } from "./routeTree.gen.ts"
|
||||
|
||||
export const getRouter = () => {
|
||||
const { queryClient } = createQueryContext()
|
||||
export const createRouter = () => {
|
||||
const rqContext = createQueryContext()
|
||||
|
||||
const router = createRouter({
|
||||
return routerWithQueryClient(
|
||||
createTanstackRouter({
|
||||
routeTree,
|
||||
context: { queryClient, user: null },
|
||||
context: { ...rqContext },
|
||||
defaultPreload: "intent",
|
||||
Wrap: (props: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<QueryProvider {...{ queryClient }}>{props.children}</QueryProvider>
|
||||
)
|
||||
return <QueryProvider {...rqContext}>{props.children}</QueryProvider>
|
||||
}
|
||||
})
|
||||
|
||||
setupRouterSsrQueryIntegration({
|
||||
router,
|
||||
queryClient,
|
||||
handleRedirects: true,
|
||||
wrapQueryClient: false
|
||||
})
|
||||
|
||||
return router
|
||||
}),
|
||||
rqContext.queryClient
|
||||
)
|
||||
}
|
||||
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
router: ReturnType<typeof getRouter>
|
||||
router: ReturnType<typeof createRouter>
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,21 +7,12 @@ import {
|
||||
} from "@tanstack/react-router"
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"
|
||||
import { HeroUIProvider } from "@/integrations/heroui/provider"
|
||||
import { SonnerProvider } from "@/integrations/sonner/provider"
|
||||
import { user } from "@/lib/server/user"
|
||||
|
||||
interface MyRouterContext {
|
||||
queryClient: QueryClient
|
||||
user: null
|
||||
}
|
||||
|
||||
export const Route = createRootRouteWithContext<MyRouterContext>()({
|
||||
beforeLoad: async () => {
|
||||
const userData = await user.userData()
|
||||
return {
|
||||
...userData
|
||||
}
|
||||
},
|
||||
head: () => ({
|
||||
meta: [
|
||||
{
|
||||
@ -53,16 +44,7 @@ function RootDocument({ children }: { children: React.ReactNode }) {
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
className="min-h-screen bg-linear-to-br from-green-200 to-emerald-400"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(50% 50% at 95% 5%, #34d399 0%, #6ee7b7 70%, #f5f5f5 100%)"
|
||||
}}
|
||||
>
|
||||
<HeroUIProvider>{children}</HeroUIProvider>
|
||||
</div>
|
||||
<SonnerProvider />
|
||||
<TanStackRouterDevtools />
|
||||
<Scripts />
|
||||
</body>
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
import {
|
||||
Avatar,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownTrigger
|
||||
} from "@heroui/react"
|
||||
import { createFileRoute, Outlet } from "@tanstack/react-router"
|
||||
|
||||
export const Route = createFileRoute("/_authed")({
|
||||
beforeLoad: ({ context }) => {
|
||||
if (context.error) {
|
||||
throw new Error("Not authenticated")
|
||||
// TODO: Redirect to login page
|
||||
}
|
||||
},
|
||||
errorComponent: ({ error }) => {
|
||||
if (error.message === "Not authenticated") {
|
||||
return (
|
||||
<p>
|
||||
Not authenticated. Please <a href="/login">login</a>.
|
||||
</p>
|
||||
)
|
||||
}
|
||||
throw error
|
||||
},
|
||||
component: RouteComponent
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
const navigate = Route.useNavigate()
|
||||
return (
|
||||
<div>
|
||||
<nav className="flex gap-2 p-2 mb-2 rounded-md bg-clip-padding backdrop-filter backdrop-blur-xl bg-opacity-10 sticky top-0 z-20">
|
||||
<div className="w-full justify-between flex items-center">
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Avatar isBordered src="/profile.png" />
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
onAction={(key) => {
|
||||
if (key === "exit") {
|
||||
navigate({ to: "/logout" })
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DropdownItem color="danger" key="exit">
|
||||
Logout
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div></div>
|
||||
</nav>
|
||||
<Outlet />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
|
||||
export const Route = createFileRoute("/_authed/dashboard")({
|
||||
component: RouteComponent
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
const { user } = Route.useRouteContext()
|
||||
console.log(user)
|
||||
return <div>Dashboard</div>
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
import logo from "@assets/logo.svg"
|
||||
import { Button } from "@heroui/react"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
@ -7,7 +6,6 @@ export const Route = createFileRoute("/")({
|
||||
})
|
||||
|
||||
function App() {
|
||||
const navigate = Route.useNavigate()
|
||||
return (
|
||||
<div className="text-center">
|
||||
<header className="min-h-screen flex flex-col items-center justify-center bg-[#282c34] text-white text-[calc(10px+2vmin)]">
|
||||
@ -19,26 +17,22 @@ function App() {
|
||||
<p>
|
||||
Edit <code>src/routes/index.tsx</code> and save to reload.
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||
<Button
|
||||
onPress={() =>
|
||||
navigate({
|
||||
to: "/login"
|
||||
})
|
||||
}
|
||||
<a
|
||||
className="text-[#61dafb] hover:underline"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => {
|
||||
navigate({
|
||||
to: "/signup"
|
||||
})
|
||||
}}
|
||||
Learn React
|
||||
</a>
|
||||
<a
|
||||
className="text-[#61dafb] hover:underline"
|
||||
href="https://tanstack.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Signup
|
||||
</Button>
|
||||
</div>
|
||||
Learn TanStack
|
||||
</a>
|
||||
</header>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
import { Button, Form, Input } from "@heroui/react"
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router"
|
||||
import type { FormEvent } from "react"
|
||||
import { useLogin } from "@/lib/hooks/user/useLogin"
|
||||
|
||||
export const Route = createFileRoute("/login")({
|
||||
beforeLoad: ({ context }) => {
|
||||
if (!context?.error) {
|
||||
throw redirect({
|
||||
to: "/dashboard"
|
||||
})
|
||||
// TODO: Redirect to login page
|
||||
}
|
||||
},
|
||||
component: LoginComp
|
||||
})
|
||||
|
||||
function LoginComp() {
|
||||
const { errors, isPending, login } = useLogin()
|
||||
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
const formData = new FormData(e.currentTarget)
|
||||
|
||||
login({
|
||||
email: formData.get("email") as string,
|
||||
password: formData.get("password") as string
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center flex-col h-screen">
|
||||
<p className="font-semibold mb-3">Login</p>
|
||||
<Form
|
||||
validationErrors={errors}
|
||||
className="grid gap-2 max-w-sm w-full"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<Input name="email" label="Email" />
|
||||
<Input name="password" type="password" label="Password" />
|
||||
<Button type="submit" isLoading={isPending}>
|
||||
Entrar
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { user } from "@/lib/server/user"
|
||||
|
||||
export const Route = createFileRoute("/logout")({
|
||||
beforeLoad: async () => {
|
||||
await user.logout()
|
||||
},
|
||||
preload: false
|
||||
})
|
||||
@ -1,35 +0,0 @@
|
||||
import { Button } from "@heroui/react"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { places } from "@/lib/server/places"
|
||||
import { user } from "@/lib/server/user"
|
||||
|
||||
export const Route = createFileRoute("/places")({
|
||||
component: RouteComponent
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
const submitUser = async () => {
|
||||
const userId = await user.userData()
|
||||
await places.insertUserPlace({
|
||||
data: {
|
||||
name: "Place 1",
|
||||
description: "A nice place",
|
||||
coord_x: "40.7128",
|
||||
coord_y: "-74.0060",
|
||||
id_user: userId.user?.id as string, // Replace with actual user ID
|
||||
hidden_place: false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const fetchPlaces = async () => {
|
||||
const allPlacesByUser = await places.getUserPlacesById()
|
||||
console.log(allPlacesByUser)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onPress={fetchPlaces}>Click</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
import { Button, Form, Input } from "@heroui/react"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import type { FormEvent } from "react"
|
||||
import { useSignup } from "@/lib/hooks/user/useSignup"
|
||||
|
||||
export const Route = createFileRoute("/signup")({
|
||||
component: SignupComp
|
||||
})
|
||||
|
||||
function SignupComp() {
|
||||
const { signup, errors, isPending } = useSignup()
|
||||
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
|
||||
const formData = new FormData(e.currentTarget)
|
||||
|
||||
signup({
|
||||
email: formData.get("email") as string,
|
||||
password: formData.get("password") as string,
|
||||
name: formData.get("nombre") as string,
|
||||
location: formData.get("location") as string
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center flex-col h-screen">
|
||||
<p className="font-semibold mb-3">Signup</p>
|
||||
<Form
|
||||
validationErrors={errors}
|
||||
className="grid gap-2 max-w-sm w-full"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<Input name="email" type="email" label="Email" />
|
||||
<Input name="password" type="password" label="Password" />
|
||||
<Input name="nombre" label="Name" />
|
||||
<Input name="location" label="Location" />
|
||||
<Button type="submit" isLoading={isPending}>
|
||||
Enviar
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Luckiest+Guy&family=Outfit:wght@100..900&family=Rubik+Vinyl&display=swap');
|
||||
@import "tailwindcss";
|
||||
@plugin '../integrations/heroui/heroui.ts';
|
||||
|
||||
@ -14,15 +13,7 @@ body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--font-outfit: "Outfit", sans-serif;
|
||||
--font-rubik-vinyl: "Rubik Vinyl", cursive;
|
||||
--font-luckiest-guy: "Luckiest Guy", cursive;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family:
|
||||
source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": false,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
|
||||
@ -10,7 +10,9 @@ const config = defineConfig({
|
||||
projects: ['./tsconfig.json'],
|
||||
}),
|
||||
tailwindcss(),
|
||||
tanstackStart(),
|
||||
tanstackStart({
|
||||
customViteReactPlugin: true,
|
||||
}),
|
||||
viteReact(),
|
||||
],
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user