diff --git a/.cspell.json b/.cspell.json index 88770e2..4257212 100644 --- a/.cspell.json +++ b/.cspell.json @@ -1,30 +1,22 @@ { "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", "version": "0.2", - "ignorePaths": ["node_modules", "/package.json"], + "ignorePaths": [ + "node_modules", + "src/types/supabase.gen.ts", + "/package.json" + ], "words": [ "Aichi", "backburger", "cloudflare", "consts", - "cloudflare", - "consts", - "cloudflare", - "consts", + "DKKI", "envsafe", - "fontsource", - "gemini", - "fontsource", - "fontsource", "gemini", "Hstack", "iconify", "instagram", - "jetbrains", - "lottie", - "lottiefiles", - "neverthrow", - "instagram", "neverthrow", "pandacss", "supabase", diff --git a/.env b/.env index 01c7ab8..f8dbc0a 100644 --- a/.env +++ b/.env @@ -13,3 +13,4 @@ VITE_GEMINI_API_KEY="encrypted:BBcfg5FvxzqtXAWYLmIVSrEY7E2W7pjQJW+9ZJA8B9PGZR1qI SUPABSE_AUTH_GOOGLE_CLIENT_ID="encrypted:BH2gXi+3RVRhmjuc0L4yFX3ZQ5MpgXcYnnRZ2RM7V0gijmvso76UJkcedzEl0W1ign+uF+xXYq/cNJ3quh+rAXzuBEH3EIwr+KFUXtUUZRhVfQgqG4pbDlvtUxlLMW0WZSDBQtrfUtINBATrVLmJm4c5viXJ/sdIaMMDqGN48/L+EoGXzdNmDNUZrvZAd6qLwrVm9QtQmW+eIhPeE34f6ofcrudLYbxIUg==" SUPABSE_AUTH_GOOGLE_CLIENT_SECRET="encrypted:BGdglht6PhNgampfxpYHbL/mmIpirBexAwv/IvH1pdP0BwjZxiMdvAugocijOmXdw/1tFrQFtvA5z4ebQ1FUfh7kmlDQfkKdkvxBvJPD4yyxAoW9diNBF99c65VejZVrvDW4NEJa7iRgD0OHyR4niaScRXksyE39zfMFSoCrclavYUnh" YAHOO_REV_GEO_API_KEY="encrypted:BLPKxHwlqs3jKdEK2PEoaDiMan1p7H1m/4YhEnctF8VCoWL5Yp83iFF8DqqRf7aVGTQtfSsu8QNQEociZ28BC1P3SCCzQ7lXWCT+bGAtoGc9Gab9LK02F2x9xhthYXDaQ/l3SxcBqLNPmI3gAF5BCoE6zeoF3Uyw0vpORhiSjCXfJPEmAxl81cb36Q7010lR2b9IQ2wxlL4B" +ADDR_REFERER_URL="http://127.0.0.1:5173" diff --git a/.env.production b/.env.production index c97fbd1..f3ada7a 100644 --- a/.env.production +++ b/.env.production @@ -6,3 +6,4 @@ DOTENV_PUBLIC_KEY_PRODUCTION="02158caa476f67de708aa5d29234e73a9ee18d586e14bb3716 # .env.production VITE_SUPABASE_URL="encrypted:BLiNk1AbwSiE+TBRMmMEShJP+zjdZ2EjTAMZClzcFHU+Sv0QBqPRlDFoEKLr1AackHwepKq+XMEw8MIU4s7Ay29COFlcoI9QJjUKMUBLf3vCeVJcDlvWmBB7dnfB6IInKJGCQ/j6CYl8pDzXqH/veUHGw4CytPpWx9RSWEMLmSCQ5fnf7nFg4E4=" +ADDR_REFERER_URL="https://wkb.pages.dev" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..563ccc2 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,67 @@ +name: cloudflare + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + if: contains(github.event.head_commit.message, '[skip ci]') == false + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v3 + + - name: 📸 Calculate commit hash + id: sha + uses: pr-mpt/actions-commit-hash@v2 + + - name: 🔨 Prepare Node environment + uses: actions/setup-node@v4 + with: + node-version: 22 + - name: 🔨 Prepare Bun environment + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: 🎉 Install project dependencies + run: bun i + + - name: 🔏 Decrypt .envs + run: bun dotenvx decrypt -f .env -f .env.production + env: + DOTENV_PRIVATE_KEY: ${{ secrets.DOTENV_PRIVATE_KEY }} + DOTENV_PRIVATE_KEY_PRODUCTION: ${{ secrets.DOTENV_PRIVATE_KEY_PRODUCTION }} + + - name: 🏗️ Build app + run: bun run build + + - name: 🚀 Deploy to Cloudflare Pages + id: cloudflare_pages_deploy + uses: cloudflare/wrangler-action@2.0.0 + with: + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + command: "pages deploy . --project-name wkb" + workingDirectory: ./dist + env: + NODE_VERSION: 22 + + - name: 🚀 Deploy pages based on commit sha + uses: actions/github-script@v6 + with: + script: | + const sha = context.payload.pull_request?.head.sha ?? context.sha; + await github.rest.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + context: "cloudflare / build (push)", + description: "Commit based deploy", + state: "success", + sha, + target_url: "https://wkb.pages.dev", + }); diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b5a65f8 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,28 @@ +name: test + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + if: contains(github.event.head_commit.message, '[skip ci]') == false + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v3 + + - name: 🔨 Prepare Bun environment + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - run: curl -sfS https://dotenvx.sh/install.sh | sh + + - name: 🎉 Install project dependencies + run: bun i + + - name: 😺 Check + run: bun run test diff --git a/.gitignore b/.gitignore index 769d83e..df54b93 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,6 @@ dist-ssr /panda/ src/routeTree.gen.ts .env.keys -src/types/supabase.gen.ts + tsconfig.tsbuildinfo .wrangler/ diff --git a/.prettierignore b/.prettierignore index 14784e1..bb412fe 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ src/assets/animations/* +functions/tsconfig.json diff --git a/functions/__lib/consts.ts b/functions/__lib/consts.ts index 66a10a4..2492726 100644 --- a/functions/__lib/consts.ts +++ b/functions/__lib/consts.ts @@ -1,5 +1,6 @@ export type Env = { YAHOO_REV_GEO_API_KEY: string; + ADDR_REFERER_URL: string; }; export function getEnv(env: Partial, key: T): Env[T] { @@ -11,11 +12,11 @@ export function getEnv(env: Partial, key: T): Env[T] { return value; } -export function getDefaultCors(esaAppRedirectUri: string): Response { +export function getDefaultCors(ADDR_REFERER_URL: string): Response { return new Response(null, { status: 204, headers: { - "Access-Control-Allow-Origin": new URL(esaAppRedirectUri).origin, + "Access-Control-Allow-Origin": new URL(ADDR_REFERER_URL).origin, "Access-Control-Allow-Headers": "*", "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Max-Age": "86400", diff --git a/functions/address.ts b/functions/address.ts index ac40688..4445bd9 100644 --- a/functions/address.ts +++ b/functions/address.ts @@ -1,6 +1,9 @@ import type { PagesFunction } from "@cloudflare/workers-types"; import { z } from "zod"; -import { type Env } from "./__lib/consts.js"; +import { getDefaultCors, type Env } from "./__lib/consts.js"; + +export const onRequestOptions: PagesFunction = async ({ env }) => + getDefaultCors(env.ADDR_REFERER_URL); export const onRequest: PagesFunction = async ({ request, env }) => { if (request.method !== "GET") { diff --git a/package.json b/package.json index e3cdc84..d3ad560 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "prepare": "panda codegen", "dev": "dotenvx run -- bun vite", "dev:workers": "dotenvx run -- wrangler pages dev --ip 127.0.0.1 --port 5173 -- bun run dev", - "build": "dotenvx run -- bun tsc -b && vite build && bunx cpx wrangler.toml dist/ && bunx cpx \"functions/**\" dist/functions", + "build": "dotenvx run -f .env -f .env.production --overload -- bun run test && vite build && bunx cpx wrangler.toml dist/ && bunx cpx \"functions/**\" dist/functions", "preview": "vite preview", - "test": "tsc && bun typo && prettier --check ./src/ ./functions/ --check && eslint --ext .ts,.tsx ./src ./functions/ ", + "test": "bun tsr generate && bun tsc -b && bun typo && prettier --check ./src/ ./functions/ --check && eslint --ext .ts,.tsx ./src ./functions/ ", "fmt": "prettier --write ./src/", "lint": "eslint --ext .ts,.tsx ./src", "typo": "cspell \"./src/**\" \"./functions/**\" --gitignore", @@ -33,7 +33,6 @@ "@lottiefiles/react-lottie-player": "^3.5.4", "@supabase/supabase-js": "^2.45.4", "@types/leaflet": "^1.9.12", - "axios": "^1.7.7", "envsafe": "^2.0.3", "i18next": "^23.15.1", "jotai": "^2.9.3", @@ -55,6 +54,7 @@ "@eslint/js": "^9.9.0", "@pandacss/dev": "^0.46.0", "@pandacss/eslint-plugin": "^0.1.11", + "@tanstack/router-cli": "^1.58.1", "@tanstack/router-devtools": "^1.57.10", "@tanstack/router-plugin": "^1.57.9", "@tsconfig/strictest": "^2.0.5", diff --git a/src/assets/data.ts b/src/assets/data.ts index 7cfbc6d..e6fccc3 100644 --- a/src/assets/data.ts +++ b/src/assets/data.ts @@ -76,141 +76,164 @@ export const categoriesData: Array> = [ }, ]; -export const projectsData: Array & { seed_id: number[] }> = - [ - { - category_id: "1", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "屋上庭園を併設し、多様な休憩に対応できる複合施設。ヨガや読書スペース、カフェコーナーを設置。自然光を取り入れた開放的な空間設計。", - key_visual: null, - name: "憩いの丘", - project_id: "1", - territory_id: "1", - seed_id: [1, 2, 3], - }, - { - category_id: "1", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "緑豊かな庭園の中に、コンパクトなブックカフェを設置。ハンモックやソファなど、ゆったりと読書を楽しめるスペースを多数用意。", - key_visual: null, - name: "本の森カフェ", - project_id: "2", - territory_id: "1", - seed_id: [2, 4], - }, - { - category_id: "1", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00-00-00Z", - description: - "自然の音に包まれ、瞑想やヨガに集中できる静かなスペース。人工芝や木陰など、自然素材を取り入れた癒やしの空間。", - key_visual: null, - name: "静寂の庭", - project_id: "3", - territory_id: "1", - seed_id: [3, 5, 6], - }, - { - category_id: "3", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "地元の農産物を使い、安価で美味しい食事を提供するレストランをオープンする", - key_visual: null, - name: "地元食材レストラン", - project_id: "4", - territory_id: "1", - seed_id: [7, 8], - }, - { - category_id: "6", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "若者向けの起業支援センターを設立し、起業家育成と地域経済の活性化を促進します。", - key_visual: null, - name: "若者向け起業支援センター設立", - project_id: "5", - territory_id: "1", - seed_id: [9, 16], - }, - { - category_id: "3", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "地元の高齢者が運営する昔ながらの食堂をオープンし、地域の味を守り、世代間交流を促進します。", - key_visual: null, - name: "昔ながらの食堂", - project_id: "6", - territory_id: "1", - seed_id: [10, 12, 15], - }, - { - category_id: "2", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "空き家をリノベーションし、コミュニティスペースとして活用することで、地域交流の活性化を目指します。", - key_visual: null, - name: "空き家活用コミュニティスペース", - project_id: "7", - territory_id: "1", - seed_id: [11, 14, 18], - }, - { - category_id: "3", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "地元の食材を使った料理教室を定期的に開催し、食文化の継承と地域産業の活性化を目指します。", - key_visual: null, - name: "地元食材料理教室", - project_id: "8", - territory_id: "1", - seed_id: [10, 12], - }, - { - category_id: "4", - created_at: "2024-09-22T00:00:00Z", - deadline: "2024-10-22T00:00:00Z", - description: - "地元の農家から直接新鮮な食材を仕入れ地域特産品を販売する、賑わいのあるマルシェ。", - key_visual: null, - name: "地域特産品マルシェ", - project_id: "9", - territory_id: "1", - seed_id: [13, 17], - }, - ]; +export const projectsData: Array< + DBSchema<"projects"> & { + amount_of_money: number; + seed_id: number[]; + location: { lon: number; lat: number }; + } +> = [ + { + category_id: "1", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "屋上庭園を併設し、多様な休憩に対応できる複合施設。ヨガや読書スペース、カフェコーナーを設置。自然光を取り入れた開放的な空間設計。", + key_visual: null, + name: "憩いの丘", + project_id: "1", + territory_id: "1", + seed_id: [1, 2, 3], + amount_of_money: 12000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "1", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "緑豊かな庭園の中に、コンパクトなブックカフェを設置。ハンモックやソファなど、ゆったりと読書を楽しめるスペースを多数用意。", + key_visual: null, + name: "本の森カフェ", + project_id: "2", + territory_id: "1", + seed_id: [2, 4], + amount_of_money: 1000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "1", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00-00-00Z", + description: + "自然の音に包まれ、瞑想やヨガに集中できる静かなスペース。人工芝や木陰など、自然素材を取り入れた癒やしの空間。", + key_visual: null, + name: "静寂の庭", + project_id: "3", + territory_id: "1", + seed_id: [3, 5, 6], + amount_of_money: 2000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "3", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "地元の農産物を使い、安価で美味しい食事を提供するレストランをオープンする", + key_visual: null, + name: "地元食材レストラン", + project_id: "4", + territory_id: "1", + seed_id: [7, 8], + amount_of_money: 3000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "6", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "若者向けの起業支援センターを設立し、起業家育成と地域経済の活性化を促進します。", + key_visual: null, + name: "若者向け起業支援センター設立", + project_id: "5", + territory_id: "1", + seed_id: [9, 16], + amount_of_money: 24000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "3", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "地元の高齢者が運営する昔ながらの食堂をオープンし、地域の味を守り、世代間交流を促進します。", + key_visual: null, + name: "昔ながらの食堂", + project_id: "6", + territory_id: "1", + seed_id: [10, 12, 15], + amount_of_money: 53000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "2", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "空き家をリノベーションし、コミュニティスペースとして活用することで、地域交流の活性化を目指します。", + key_visual: null, + name: "空き家活用コミュニティスペース", + project_id: "7", + territory_id: "1", + seed_id: [11, 14, 18], + amount_of_money: 12000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "3", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "地元の食材を使った料理教室を定期的に開催し、食文化の継承と地域産業の活性化を目指します。", + key_visual: null, + name: "地元食材料理教室", + project_id: "8", + territory_id: "1", + seed_id: [10, 12], + amount_of_money: 32000, + location: { lon: 136.886326, lat: 35.172757 }, + }, + { + category_id: "4", + created_at: "2024-09-22T00:00:00Z", + deadline: "2024-10-22T00:00:00Z", + description: + "地元の農家から直接新鮮な食材を仕入れ地域特産品を販売する、賑わいのあるマルシェ。", + key_visual: null, + name: "地域特産品マルシェ", + project_id: "9", + territory_id: "1", + seed_id: [13, 17], + amount_of_money: 10000, + location: { lon: 136.886326, lat: 35.172757 }, + }, +]; export const sponsorDataData: Array< DBSchema<"sponsor_data"> & { - reports: Array>; + reports?: Array>; fruits: Array>; } > = [ { created_at: "2024-09-22T00:00:00Z", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sponsor_id: "1", motivation: "スポンサー1のモチベーション", - project_id: "1", - target_amount_of_money: 1000, + project_id: "7", + target_amount_of_money: 10000, reports: [ { - body: "スポンサー1のレポート", - created_at: "2024-09-22T00:00:00Z", - key_visual: "https://via.placeholder.com/150", - project_id: "1", - report_id: "1", - sponsor_id: "1", - title: "スポンサー1のレポート", - } + body: "スポンサー1のレポート", + created_at: "2024-09-22T00:00:00Z", + key_visual: "https://via.placeholder.com/150", + project_id: "1", + report_id: "1", + sponsor_id: "1", + title: "スポンサー1のレポート", + }, ], fruits: [ { @@ -223,8 +246,68 @@ export const sponsorDataData: Array< project_id: "1", sponsor_id: "1", }, + { + fruit_id: "2", + name: "バナナ", + created_at: "2024-09-22T00:00:00Z", + description: "バナナの説明", + amount_of_money: 2000, + key_visual: "https://via.placeholder.com/150", + project_id: "1", + sponsor_id: "1", + }, + { + fruit_id: "3", + name: "いちご", + created_at: "2024-09-22T00:00:00Z", + description: "いちごの説明", + amount_of_money: 3000, + key_visual: "https://via.placeholder.com/150", + project_id: "1", + sponsor_id: "1", + }, ], - }, + }, + { + created_at: "2024-09-22T00:00:00Z", + location: { lon: 136.886326, lat: 35.172757 }, + sponsor_id: "1", + motivation: "スポンサー1のモチベーション", + project_id: "1", + target_amount_of_money: 100000, + fruits: [ + { + fruit_id: "4", + name: "りんご", + created_at: "2024-09-22T00:00:00Z", + description: "りんごの説明", + amount_of_money: 1000, + key_visual: "https://via.placeholder.com/150", + project_id: "2", + sponsor_id: "1", + }, + { + fruit_id: "5", + name: "バナナ", + created_at: "2024-09-22T00:00:00Z", + description: "バナナの説明", + amount_of_money: 2000, + key_visual: "https://via.placeholder.com/150", + project_id: "2", + sponsor_id: "1", + }, + { + fruit_id: "6", + name: "いちご", + created_at: "2024-09-22T00:00:00Z", + description: "いちごの説明", + amount_of_money: 3000, + key_visual: "https://via.placeholder.com/150", + project_id: "2", + sponsor_id: "1", + }, + ], + }, ]; export const seedsData: Array> = [ @@ -232,7 +315,7 @@ export const seedsData: Array> = [ seed_id: "1", created_at: "2024-09-22T00:00:00Z", description: "屋上庭園のある公共施設が欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "1", }, @@ -240,7 +323,7 @@ export const seedsData: Array> = [ seed_id: "2", created_at: "2024-09-22T00:00:00Z", description: "静かに読書できる屋外ブックカフェが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "1", }, @@ -248,7 +331,7 @@ export const seedsData: Array> = [ seed_id: "3", created_at: "2024-09-22T00:00:00Z", description: "静かに瞑想やヨガができる屋外スペースが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "1", }, @@ -256,7 +339,7 @@ export const seedsData: Array> = [ seed_id: "4", created_at: "2024-09-22T00:00:00Z", description: "公園にハンモックエリアを作ってほしい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "1", }, @@ -264,7 +347,7 @@ export const seedsData: Array> = [ seed_id: "5", created_at: "2024-09-22T00:00:00Z", description: "人工芝の広がる場所がほしい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "4", }, @@ -272,7 +355,7 @@ export const seedsData: Array> = [ seed_id: "7", created_at: "2024-09-22T00:00:00Z", description: "地元の農産物を使った安くて美味しいレストランが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "3", }, @@ -280,7 +363,7 @@ export const seedsData: Array> = [ seed_id: "8", created_at: "2024-09-22T00:00:00Z", description: "新鮮な野菜を使ったレストランが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "3", }, @@ -288,7 +371,7 @@ export const seedsData: Array> = [ seed_id: "9", created_at: "2024-09-22T00:00:00Z", description: "若者向けの起業支援センターが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "6", }, @@ -296,7 +379,7 @@ export const seedsData: Array> = [ seed_id: "10", created_at: "2024-09-22T00:00:00Z", description: "地元の農産物を使った安くて美味しいレストランが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "3", }, @@ -304,7 +387,7 @@ export const seedsData: Array> = [ seed_id: "11", created_at: "2024-09-22T00:00:00Z", description: "コミュニティスペースを増やしてほしい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "2", }, @@ -312,7 +395,7 @@ export const seedsData: Array> = [ seed_id: "12", created_at: "2024-09-22T00:00:00Z", description: "地元の食材を使った料理教室が定期的に開かれる場所が欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "4", }, @@ -320,7 +403,7 @@ export const seedsData: Array> = [ seed_id: "13", created_at: "2024-09-22T00:00:00Z", description: "地元の農家と直接つながる朝市を定期的に開催してほしい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "3", }, @@ -328,7 +411,7 @@ export const seedsData: Array> = [ seed_id: "14", created_at: "2024-09-22T00:00:00Z", description: "多世代が交流できるコミュニティガーデンが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "6", }, @@ -336,7 +419,7 @@ export const seedsData: Array> = [ seed_id: "15", created_at: "2024-09-22T00:00:00Z", description: "地元の高齢者が運営する昔ながらの食堂が欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "4", }, @@ -344,7 +427,7 @@ export const seedsData: Array> = [ seed_id: "16", created_at: "2024-09-22T00:00:00Z", description: "地域の経済を活性化させたい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "6", }, @@ -352,7 +435,7 @@ export const seedsData: Array> = [ seed_id: "17", created_at: "2024-09-22T00:00:00Z", description: "地域の特産品を販売する常設マルシェが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "4", }, @@ -360,7 +443,7 @@ export const seedsData: Array> = [ seed_id: "18", created_at: "2024-09-22T00:00:00Z", description: "地域の人々が集まれるコミュニティスペースが欲しい", - location: { lat: 35.688, lng: 139.69 }, + location: { lon: 136.886326, lat: 35.172757 }, sower_id: "1", category_id: "6", }, diff --git a/src/components/project/Card.tsx b/src/components/project/Card.tsx index 79c1edb..4a65f7c 100644 --- a/src/components/project/Card.tsx +++ b/src/components/project/Card.tsx @@ -1,64 +1,96 @@ import { Icon } from "@iconify/react"; import { styled as p, HStack } from "panda/jsx"; - import { type ReactElement } from "react"; +import useSWRImmutable from "swr/immutable"; +import { match } from "ts-pattern"; import { ICON } from "@/assets/icon"; +import { Loading } from "@/components/Loading"; +import { Expanded } from "@/components/cva/Expanded"; +import { fetchAddressFromLocation } from "@/lib/services/address"; +import { S } from "@/lib/utils/patterns"; export function ProjectCard({ name, - keyVisual, + // eslint-disable-next-line @typescript-eslint/naming-convention + key_visual, location, - amountOfMoney, + // eslint-disable-next-line @typescript-eslint/naming-convention + amount_of_money, status, }: { name: string; - location: string; - amountOfMoney: number; + location: { + lat: number; + lon: number; + }; + amount_of_money: number; status: "wakaba" | "seed" | "tree"; - keyVisual: string; + key_visual: string; }): ReactElement { - return ( - - - - - - - - - {location} + const swrLocation = useSWRImmutable("location", async () => + ( + await fetchAddressFromLocation({ + lat: location.lat, + lon: location.lon, + }) + )._unsafeUnwrap(), + ); + + return match(swrLocation) + .with(S.Loading, () => ( + + + わかばの起動中... + + + )) + .with(S.Success, ({ data: { Feature } }) => ( + + + + + + + + + {status === "wakaba" + ? `${Feature.at(0)?.Property.AddressElement[2]?.Name}周辺` + : Feature.at(0)?.Property.AddressElement[2]?.Name ?? + `${Feature.at(0)?.Property.AddressElement[3]?.Name}` ?? + ""} + + + {name} + 現在金額 ¥{amount_of_money} + + + + + + - - {name} - 現在金額 ¥{amountOfMoney} - - - - - - - + - - ); + )) + .otherwise(({ error }) => {error.Error.Message}); } diff --git a/src/components/sva/dialog.ts b/src/components/sva/dialog.ts index a64c826..00b6765 100644 --- a/src/components/sva/dialog.ts +++ b/src/components/sva/dialog.ts @@ -44,7 +44,7 @@ export const svaDialog = sva({ }, backdrop: { animation: "fadeIn 0.3s", - backgroundColor: "rgba(0, 0, 0, 0.5)", + backgroundColor: "wkb-neutral.0/20", position: "fixed", top: 0, left: 0, diff --git a/src/lib/classes/user.ts b/src/lib/classes/user.ts index 93616c6..a1e1fd9 100644 --- a/src/lib/classes/user.ts +++ b/src/lib/classes/user.ts @@ -6,10 +6,13 @@ import { notifyErrorInToast, toaster } from "@/lib/utils/toast"; import { type UserMetadata } from "@/types/auth"; export class User { - constructor(public session: Session) {} + public metadata: UserMetadata; + public id: string; - public metadata = this.session.user.user_metadata as UserMetadata; - public id = this.session.user.id; + constructor(public session: Session) { + this.metadata = this.session.user.user_metadata as UserMetadata; + this.id = this.session.user.id; + } static async signIn(): Promise { match( diff --git a/src/routes/_auth/projects/$uuid.tsx b/src/routes/_auth/projects/$uuid.tsx index d8365c2..95777a2 100644 --- a/src/routes/_auth/projects/$uuid.tsx +++ b/src/routes/_auth/projects/$uuid.tsx @@ -3,11 +3,23 @@ import { Icon } from "@iconify/react/dist/iconify.js"; import { createFileRoute } from "@tanstack/react-router"; import { Flex, Grid, HStack, styled as p, VStack } from "panda/jsx"; import { type ReactElement, useRef } from "react"; +import useSWRImmutable from "swr/immutable"; +import { match } from "ts-pattern"; import { FruitCard } from "./-components/Fruit"; import { ReportCard } from "./-components/Report"; +import { + projectsData, + sponsorDataData, + sponsorsData, + seedsData, +} from "@/assets/data"; import { ICON } from "@/assets/icon"; +import { Loading } from "@/components/Loading"; +import { Expanded } from "@/components/cva/Expanded"; import { svaDialog } from "@/components/sva/dialog"; import { svaProgress } from "@/components/sva/progress"; +import { fetchAddressFromLocation } from "@/lib/services/address"; +import { S } from "@/lib/utils/patterns"; type needs = { amount_of_money: number; @@ -21,38 +33,46 @@ type needs = { description: string; location: { lat: number; - lng: number; + lon: number; }; - sponsor_data: { - name: string; - icon: string; - target_amount_of_money: number; - location: { - lat: number; - lng: number; - }; - motivation: string; - }; - reports: Array<{ - body: string; - key_visual: string; - report_id: string; - title: string; - created_at: string; - }>; - fruits: Array<{ - description: string; - key_visual: string; - name: string; - }>; - comments: Array<{ - body: string; - comment_id: string; - created_at: string; - user_id: string; - }>; + sponsor: + | { + created_at: string; + description: string | null; + icon: string; + name: string; + sponsor_id: string; + user_id: string; + } + | undefined; + sponsor_data: + | { + target_amount_of_money: number; + location?: { + lat: number; + lon: number; + }; + motivation: string | undefined; + reports?: + | Array<{ + body: string; + key_visual: string | null; + report_id: string; + title: string; + created_at: string; + }> + | undefined; + fruits?: + | Array<{ + description: string; + key_visual: string | null; + name: string; + }> + | undefined; + } + | undefined; seeds: Array<{ - category_ids: string[]; + category_id: string; created_at: string; description: string | null; location: unknown; @@ -79,330 +99,311 @@ function GridDetailInfo({ scrollRef?.current?.scrollIntoView(); }; - return ( - - - - {data?.name} - - - - - {data?.name} - - - 残り{leftDays}日 - + const swrLocation = useSWRImmutable("location", async () => + ( + await fetchAddressFromLocation({ + lat: data.location.lat, + lon: data.location.lon, + }) + )._unsafeUnwrap(), + ); + + return match(swrLocation) + .with(S.Loading, () => ( + + + わかばの起動中... + + + )) + .with(S.Success, ({ data: { Feature } }) => ( + + + + {data?.name} + + + + + {data?.name} + + + 残り{leftDays}日 + + + + + + + + + - - - + {data.description} + + + + + + + + {data.status === "wakaba" + ? `${Feature.at(0)?.Property.AddressElement[2]?.Name}周辺` + : Feature.at(0)?.Property.AddressElement[2]?.Name ?? + `${Feature.at(0)?.Property.AddressElement[3]?.Name}` ?? + ""} + + - - + + 支援進捗 + + + + ¥ {data.amount_of_money.toLocaleString()} + + - {data.description} - - - - - - 緯度経度算出住所 - - - - - 支援進捗 - - - - ¥ {data.amount_of_money.toLocaleString()} - - - + + {data.status !== "wakaba" && data.sponsor_data !== undefined && ( + + 目標金額 ¥ + {data.sponsor_data.target_amount_of_money.toLocaleString()} + + )} + - {data.status !== "wakaba" && ( - - 目標金額 ¥ - {data.sponsor_data.target_amount_of_money.toLocaleString()} - + = 100 ? percentage : 100} + value={percentage} + > + + + {percentage >= 20 && ( + + {percentage}% + + )} + + + )} - - {data.status !== "wakaba" && ( - = 100 ? percentage : 100} - value={percentage} + { + scrollFruits(); + }} + px={2} + py={4} + rounded="md" > - - - {percentage >= 20 && ( - - {percentage}% - - )} - - - - )} - - { - scrollFruits(); - }} - px={2} - py={4} - rounded="md" - > - - - - {data.status === "wakaba" && "このWakabaを支援する"} - {data.status === "seed" && "このSeedを支援する"} - {data.status === "tree" && "このTreeを支援する"} - - - + + + + {data.status === "wakaba" && "このWakabaを支援する"} + {data.status === "seed" && "このSeedを支援する"} + {data.status === "tree" && "このTreeを支援する"} + + + - - 以下の意見が集まって生成されました - - - {data.seeds.map((s) => ( - - - + 以下の意見が集まって生成されました + + + {data.seeds.map((s) => ( + - {s.description} - - - ))} - + + + {s.description} + + + ))} + - - - + - {data.status !== "wakaba" ? ( - <> - - - {data.sponsor_data.name} - - + {data.status !== "wakaba" && + data.sponsor !== undefined && + data.sponsor_data !== undefined ? ( + <> + + + {data.sponsor.name} + + + {data.sponsor_data.motivation} + + + + + ) : ( + スポンサー募集中 + )} + + + + + + + {data.sponsor !== undefined && + data.sponsor_data !== undefined && ( + - {data.sponsor_data.motivation} - - - - - ) : ( - スポンサー募集中 - )} - - - - - - - - - - {data.sponsor_data.name} - - {data.sponsor_data.motivation} - - - - - - - + + + {data.sponsor.name} + + + {data.sponsor_data.motivation} + + + + + )} + + + + - - - - このプロジェクトは - - ALL or nothing - - であり、目標金額に満たなかった時は返金し、達した場合にのみプロジェクトの実行とリターンを約束するというものです。 - - - - - - ); + + + + このプロジェクトは + + ALL or nothing + + であり、目標金額に満たなかった時は返金し、達した場合にのみプロジェクトの実行とリターンを約束するというものです。 + + + + + + )) + .otherwise(({ error }) => {error.Error.Message}); } export const Route = createFileRoute("/_auth/projects/$uuid")({ component: () => { + const { uuid } = Route.useParams(); const scrollRef = useRef(null); - const data: needs = { - amount_of_money: 200, - created_at: "2021-09-06T00:00:00Z", - deadline: "2024-09-24T00:00:00Z", - key_visual: "https://via.placeholder.com/300x150", - name: "Project 1", - project_id: "1", - sponsor_data_id: "1", - status: "tree", - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", - location: { lat: 35.688, lng: 139.69 }, - sponsor_data: { - name: "DKKI", - icon: "https://via.placeholder.com/150", - target_amount_of_money: 1000, - location: { lat: 35.688, lng: 139.69 }, - motivation: - "企業さんになぜこのプロジェクトを実行することにしたのかモチベーション、意気込みを書いてもらう場所", - }, - reports: [ - { - body: "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", - key_visual: "https://via.placeholder.com/150", - report_id: "1", - title: "タイトル", - created_at: "2021-09-06T00:00:00Z", - }, - { - body: "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", - key_visual: "https://via.placeholder.com/150", - report_id: "2", - title: "title", - created_at: "2021-09-06T00:00:00Z", - }, - ], - fruits: [ - { - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", + const data2 = projectsData.find((_) => _.project_id === uuid); + if (data2 === undefined) throw new Error("No data2 found"); - key_visual: "https://via.placeholder.com/300x150", - name: "name", - }, - { - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", + const data3 = sponsorDataData.find( + (_) => _.project_id === data2.project_id, + ); - key_visual: "https://via.placeholder.com/300x150", - name: "name2", - }, - { - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", + const data4 = sponsorsData.find((_) => _.sponsor_id === data3?.sponsor_id); - key_visual: "https://via.placeholder.com/300x150", - name: "name3", - }, - ], - comments: [ - { - body: "body", - comment_id: "1", - created_at: "2021-09-06T00:00:00Z", - user_id: "1", - }, - ], - seeds: [ - { - category_ids: ["1"], - created_at: "2021-09-06T00:00:00Z", - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", - location: { lat: 35.688, lng: 139.69 }, - seed_id: "1", - sower_id: "1", - }, - { - category_ids: ["1"], - created_at: "2021-09-06T00:00:00Z", - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", + const data5 = data2.seed_id.map((s) => { + const seed = seedsData.find((_) => _.seed_id === String(s)); + if (seed === undefined) throw new Error("No data5 found"); + return seed; + }); + if (data5 === undefined) throw new Error("No data5 found"); - location: { lat: 35.688, lng: 139.69 }, - seed_id: "2", - sower_id: "2", - }, - { - category_ids: ["1"], - created_at: "2021-09-06T00:00:00Z", - description: - "昔、あるところになかなか子どもが生まれない夫婦がいました。でも、ある時、ようやくかわいらしい男の子が産まれました。れどれ。あら、こぶなんてないじゃないの?」「おばちゃん。名前が長すぎるから、もうこぶが引っ込んじゃったよ", - location: { lat: 35.688, lng: 139.69 }, - seed_id: "3", - sower_id: "3", - }, - ], + const data: needs = { + amount_of_money: data2.amount_of_money, + created_at: data2.created_at, + deadline: data2.deadline, + key_visual: data2.key_visual ?? "", + name: data2.name, + project_id: data2.project_id, + sponsor_data_id: "1", + status: + // eslint-disable-next-line no-nested-ternary + data2.project_id === "1" + ? "seed" + : data2.project_id === "7" + ? "tree" + : "wakaba", + description: data2.description, + location: data2.location, + sponsor: data4, + sponsor_data: { + target_amount_of_money: data3?.target_amount_of_money ?? 0, + location: data2.location, + motivation: data3?.motivation ?? undefined, + reports: data3?.reports ?? undefined, + fruits: data3?.fruits ?? undefined, + }, + seeds: data5, }; const leftDays = Math.floor( @@ -413,7 +414,11 @@ export const Route = createFileRoute("/_auth/projects/$uuid")({ 24, ); const percentage = Math.floor( - (data.amount_of_money / data.sponsor_data.target_amount_of_money) * 100, + (data.amount_of_money / + (data.sponsor_data !== undefined + ? data.sponsor_data.target_amount_of_money + : 0)) * + 100, ); return ( @@ -441,46 +446,71 @@ export const Route = createFileRoute("/_auth/projects/$uuid")({ > 支援する - - {data.fruits.map((f, index) => ( - - ))} - - - - - - レポート - - {data.reports.map((r) => ( - - - + {data.sponsor_data?.fruits !== undefined && + data.sponsor_data.fruits.length !== 0 ? ( + + {data.sponsor_data.fruits.map((f, index) => ( + ))} - - + + ) : ( + + {[1, 2, 3].map((f, index) => ( + + ))} + + )} + + {data.sponsor_data?.reports !== undefined && + data.sponsor_data.reports.length !== 0 && ( + + + + レポート + + {data.sponsor_data.reports.map((r) => ( + + + + ))} + + + )} diff --git a/src/routes/_auth/projects/index.tsx b/src/routes/_auth/projects/index.tsx index 10c7d39..63bcfcb 100644 --- a/src/routes/_auth/projects/index.tsx +++ b/src/routes/_auth/projects/index.tsx @@ -1,8 +1,9 @@ import { Tabs } from "@ark-ui/react"; -import { createFileRoute } from "@tanstack/react-router"; +import { createFileRoute, Link } from "@tanstack/react-router"; import { Flex, HStack, styled as p } from "panda/jsx"; import { Navigation } from "swiper/modules"; import { Swiper, SwiperSlide } from "swiper/react"; +import { projectsData } from "@/assets/data"; import { GridLayout } from "@/components/GridLayout"; import { ProjectCard } from "@/components/project/Card"; import { svaTabs } from "@/components/sva/tabs"; @@ -15,6 +16,7 @@ import "swiper/css/scrollbar"; export const Route = createFileRoute("/_auth/projects/")({ component: () => { const tabs = svaTabs(); + if (typeof window === "undefined") { return null; } @@ -50,15 +52,24 @@ export const Route = createFileRoute("/_auth/projects/")({ navigation > - {[...Array(9)].map((_) => ( - - + {projectsData.map((_) => ( + + + + ))} @@ -82,33 +93,88 @@ export const Route = createFileRoute("/_auth/projects/")({ <> - {/* //!いずれ mapでループさせる */} - - - + {projectsData + .sort((a, b) => b.amount_of_money - a.amount_of_money) + .map((_) => ( + + + + ))} + + + + + + <> + {projectsData + .sort( + (a, b) => Number(a.category_id) - Number(b.category_id), + ) + .map((_) => ( + + + + ))} + + + + + + <> + {projectsData.reverse().map((_) => ( + + + + ))} - あとで - つくるね diff --git a/src/routes/_auth/seeds/-components/SownSeed.tsx b/src/routes/_auth/seeds/-components/SownSeed.tsx index 8227279..0258ec4 100644 --- a/src/routes/_auth/seeds/-components/SownSeed.tsx +++ b/src/routes/_auth/seeds/-components/SownSeed.tsx @@ -4,6 +4,60 @@ import { type ReactElement } from "react"; import { ICON } from "@/assets/icon"; import { Button } from "@/components/cva/Button"; +export function SownSeed({ + createdAt, + category, + description, +}: { + createdAt: string; + category: string; + description: string; +}): ReactElement { + return ( + + + + + + {createdAt} + + + + + + + {description} + + + ); +} + +import { Icon } from "@iconify/react"; +import { styled as p, HStack } from "panda/jsx"; +import { type ReactElement } from "react"; +import { ICON } from "@/assets/icon"; +import { Button } from "@/components/cva/Button"; + export function SownSeed({ createdAt, category, diff --git a/src/routes/demo/-components/GeminiTest2.tsx b/src/routes/demo/-components/GeminiTest2.tsx index 768697b..23c4e7c 100644 --- a/src/routes/demo/-components/GeminiTest2.tsx +++ b/src/routes/demo/-components/GeminiTest2.tsx @@ -120,9 +120,9 @@ function Asking(): ReactElement { {JSON.stringify(data)} @@ -240,7 +240,7 @@ export function GeminiDemo2(): ReactElement { }} variant="outlined" > - Gemini に聞いてみる + Gemini に聞いてみる )} diff --git a/src/routes/demo/index.tsx b/src/routes/demo/index.tsx index 54eb8f9..80de451 100644 --- a/src/routes/demo/index.tsx +++ b/src/routes/demo/index.tsx @@ -3,17 +3,29 @@ import { css } from "panda/css"; import { VStack, styled as p } from "panda/jsx"; // NOTE: この行のスニペット: `pd` → Tab // import { PopoverSample } from "./-components/CheckBox"; // import { GeminiDemo } from "./-components/GeminiTest"; +import { useEffect } from "react"; import { GeminiDemo2 } from "./-components/GeminiTest2"; +import { fetchAddressFromLocation } from "@/lib/services/address"; // import { Logo, LogoComposite } from "@/components/Logo"; export const Route = createFileRoute("/demo/")({ - component: () => ( - h2": { fontWeight: "bold" } })} - p="2" - > - {/* + component: () => { + useEffect(() => { + void fetchAddressFromLocation({ lat: 35.681236, lon: 139.767125 }).then( + (res) => { + // eslint-disable-next-line no-console + console.log(res); + }, + ); + }, []); + + return ( + h2": { fontWeight: "bold" } })} + p="2" + > + {/* Ark UI + Atomic Slot Recipe (sva) demo @@ -30,9 +42,10 @@ export const Route = createFileRoute("/demo/")({ 複合 (4:1) ロゴ */} - Gemini API Demo - {/* */} - - - ), + Gemini API Demo + {/* */} + + + ); + }, }); diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 07f9897..c2d5d86 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,6 +1,7 @@ import { createFileRoute } from "@tanstack/react-router"; import { styled as p } from "panda/jsx"; import { useInView } from "react-intersection-observer"; + import { LogoComposite } from "@/components/Logo"; import { Button } from "@/components/cva/Button"; import { Expanded } from "@/components/cva/Expanded"; diff --git a/src/types/supabase.gen.ts b/src/types/supabase.gen.ts new file mode 100644 index 0000000..d907c34 --- /dev/null +++ b/src/types/supabase.gen.ts @@ -0,0 +1,542 @@ +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[]; + +export type Database = { + graphql_public: { + Tables: { + [_ in never]: never; + }; + Views: { + [_ in never]: never; + }; + Functions: { + graphql: { + Args: { + operationName?: string; + query?: string; + variables?: Json; + extensions?: Json; + }; + Returns: Json; + }; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; + public: { + Tables: { + categories: { + Row: { + category_id: string; + created_at: string; + description: string | null; + name: string; + }; + Insert: { + category_id?: string; + created_at?: string; + description?: string | null; + name: string; + }; + Update: { + category_id?: string; + created_at?: string; + description?: string | null; + name?: string; + }; + Relationships: []; + }; + comments: { + Row: { + body: string; + comment_id: string; + created_at: string; + project_id: string; + user_id: string; + }; + Insert: { + body: string; + comment_id?: string; + created_at?: string; + project_id: string; + user_id: string; + }; + Update: { + body?: string; + comment_id?: string; + created_at?: string; + project_id?: string; + user_id?: string; + }; + Relationships: [ + { + foreignKeyName: "comments_project_id_fkey"; + columns: ["project_id"]; + isOneToOne: false; + referencedRelation: "projects"; + referencedColumns: ["project_id"]; + }, + { + foreignKeyName: "comments_user_id_fkey"; + columns: ["user_id"]; + isOneToOne: false; + referencedRelation: "users"; + referencedColumns: ["id"]; + }, + ]; + }; + fruits: { + Row: { + amount_of_money: number; + created_at: string; + description: string; + fruit_id: string; + key_visual: string | null; + name: string; + project_id: string; + sponsor_id: string; + }; + Insert: { + amount_of_money: number; + created_at?: string; + description: string; + fruit_id?: string; + key_visual?: string | null; + name: string; + project_id: string; + sponsor_id: string; + }; + Update: { + amount_of_money?: number; + created_at?: string; + description?: string; + fruit_id?: string; + key_visual?: string | null; + name?: string; + project_id?: string; + sponsor_id?: string; + }; + Relationships: [ + { + foreignKeyName: "fruits_project_id_fkey"; + columns: ["project_id"]; + isOneToOne: false; + referencedRelation: "projects"; + referencedColumns: ["project_id"]; + }, + { + foreignKeyName: "fruits_sponsor_id_fkey"; + columns: ["sponsor_id"]; + isOneToOne: false; + referencedRelation: "sponsors"; + referencedColumns: ["sponsor_id"]; + }, + ]; + }; + pledges: { + Row: { + amount_of_money: number; + created_at: string; + pledges_id: string; + project_id: string; + sower_id: string; + }; + Insert: { + amount_of_money: number; + created_at?: string; + pledges_id?: string; + project_id: string; + sower_id: string; + }; + Update: { + amount_of_money?: number; + created_at?: string; + pledges_id?: string; + project_id?: string; + sower_id?: string; + }; + Relationships: [ + { + foreignKeyName: "pledges_project_id_fkey"; + columns: ["project_id"]; + isOneToOne: false; + referencedRelation: "projects"; + referencedColumns: ["project_id"]; + }, + { + foreignKeyName: "pledges_sower_id_fkey"; + columns: ["sower_id"]; + isOneToOne: false; + referencedRelation: "sowers"; + referencedColumns: ["sower_id"]; + }, + ]; + }; + projects: { + Row: { + category_id: string; + created_at: string; + deadline: string; + description: string; + key_visual: string | null; + name: string; + project_id: string; + territory_id: string; + }; + Insert: { + category_id: string; + created_at?: string; + deadline: string; + description: string; + key_visual?: string | null; + name: string; + project_id?: string; + territory_id: string; + }; + Update: { + category_id?: string; + created_at?: string; + deadline?: string; + description?: string; + key_visual?: string | null; + name?: string; + project_id?: string; + territory_id?: string; + }; + Relationships: [ + { + foreignKeyName: "projects_category_id_fkey"; + columns: ["category_id"]; + isOneToOne: false; + referencedRelation: "categories"; + referencedColumns: ["category_id"]; + }, + { + foreignKeyName: "projects_territory_id_fkey"; + columns: ["territory_id"]; + isOneToOne: false; + referencedRelation: "territories"; + referencedColumns: ["territory_id"]; + }, + ]; + }; + reports: { + Row: { + body: string; + created_at: string; + key_visual: string | null; + project_id: string; + report_id: string; + sponsor_id: string; + title: string; + }; + Insert: { + body: string; + created_at?: string; + key_visual?: string | null; + project_id: string; + report_id?: string; + sponsor_id: string; + title: string; + }; + Update: { + body?: string; + created_at?: string; + key_visual?: string | null; + project_id?: string; + report_id?: string; + sponsor_id?: string; + title?: string; + }; + Relationships: [ + { + foreignKeyName: "reports_project_id_fkey"; + columns: ["project_id"]; + isOneToOne: false; + referencedRelation: "projects"; + referencedColumns: ["project_id"]; + }, + { + foreignKeyName: "reports_sponsor_id_fkey"; + columns: ["sponsor_id"]; + isOneToOne: false; + referencedRelation: "sponsors"; + referencedColumns: ["sponsor_id"]; + }, + ]; + }; + seeds: { + Row: { + category_id: string; + created_at: string; + description: string | null; + location: unknown; + seed_id: string; + sower_id: string; + }; + Insert: { + category_id: string; + created_at?: string; + description?: string | null; + location: unknown; + seed_id?: string; + sower_id: string; + }; + Update: { + category_id?: string; + created_at?: string; + description?: string | null; + location?: unknown; + seed_id?: string; + sower_id?: string; + }; + Relationships: [ + { + foreignKeyName: "seeds_category_id_fkey"; + columns: ["category_id"]; + isOneToOne: false; + referencedRelation: "categories"; + referencedColumns: ["category_id"]; + }, + { + foreignKeyName: "seeds_sower_id_fkey"; + columns: ["sower_id"]; + isOneToOne: false; + referencedRelation: "sowers"; + referencedColumns: ["sower_id"]; + }, + ]; + }; + sowers: { + Row: { + birthday: string; + created_at: string; + name: string; + sower_id: string; + user_id: string; + }; + Insert: { + birthday: string; + created_at?: string; + name: string; + sower_id?: string; + user_id: string; + }; + Update: { + birthday?: string; + created_at?: string; + name?: string; + sower_id?: string; + user_id?: string; + }; + Relationships: [ + { + foreignKeyName: "users_user_id_fkey"; + columns: ["user_id"]; + isOneToOne: true; + referencedRelation: "users"; + referencedColumns: ["id"]; + }, + ]; + }; + sponsor_data: { + Row: { + created_at: string; + location: unknown; + motivation: string; + project_id: string; + sponsor_id: string; + target_amount_of_money: number; + }; + Insert: { + created_at?: string; + location: unknown; + motivation: string; + project_id: string; + sponsor_id: string; + target_amount_of_money: number; + }; + Update: { + created_at?: string; + location?: unknown; + motivation?: string; + project_id?: string; + sponsor_id?: string; + target_amount_of_money?: number; + }; + Relationships: [ + { + foreignKeyName: "sponsor_data_project_id_fkey"; + columns: ["project_id"]; + isOneToOne: true; + referencedRelation: "projects"; + referencedColumns: ["project_id"]; + }, + { + foreignKeyName: "sponsor_data_sponsor_id_fkey"; + columns: ["sponsor_id"]; + isOneToOne: false; + referencedRelation: "sponsors"; + referencedColumns: ["sponsor_id"]; + }, + ]; + }; + sponsors: { + Row: { + created_at: string; + description: string | null; + icon: string; + name: string; + sponsor_id: string; + user_id: string; + }; + Insert: { + created_at?: string; + description?: string | null; + icon: string; + name: string; + sponsor_id?: string; + user_id: string; + }; + Update: { + created_at?: string; + description?: string | null; + icon?: string; + name?: string; + sponsor_id?: string; + user_id?: string; + }; + Relationships: [ + { + foreignKeyName: "sponsors_user_id_fkey"; + columns: ["user_id"]; + isOneToOne: true; + referencedRelation: "users"; + referencedColumns: ["id"]; + }, + ]; + }; + territories: { + Row: { + created_at: string; + territory_id: string; + zone: unknown; + }; + Insert: { + created_at?: string; + territory_id?: string; + zone: unknown; + }; + Update: { + created_at?: string; + territory_id?: string; + zone?: unknown; + }; + Relationships: []; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + [_ in never]: never; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; +}; + +type PublicSchema = Database[Extract]; + +export type Tables< + PublicTableNameOrOptions extends + | keyof (PublicSchema["Tables"] & PublicSchema["Views"]) + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] & + Database[PublicTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & + Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R; + } + ? R + : never + : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & + PublicSchema["Views"]) + ? (PublicSchema["Tables"] & + PublicSchema["Views"])[PublicTableNameOrOptions] extends { + Row: infer R; + } + ? R + : never + : never; + +export type TablesInsert< + PublicTableNameOrOptions extends + | keyof PublicSchema["Tables"] + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I; + } + ? I + : never + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { + Insert: infer I; + } + ? I + : never + : never; + +export type TablesUpdate< + PublicTableNameOrOptions extends + | keyof PublicSchema["Tables"] + | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U; + } + ? U + : never + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { + Update: infer U; + } + ? U + : never + : never; + +export type Enums< + PublicEnumNameOrOptions extends + | keyof PublicSchema["Enums"] + | { schema: keyof Database }, + EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"] + : never = never, +> = PublicEnumNameOrOptions extends { schema: keyof Database } + ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] + : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] + ? PublicSchema["Enums"][PublicEnumNameOrOptions] + : never;