From bb02b1bbad5d1edb806e8d40f71a8ebb0dcd9227 Mon Sep 17 00:00:00 2001 From: farhan-helmy Date: Wed, 19 Jul 2023 21:23:18 +0800 Subject: [PATCH] fix: mall not loaded after district and state change --- .env.example | 4 - kysely/kyselyschema.ts | 121 +++ package.json | 4 +- prisma/schema.prisma | 33 +- src/components/AddSurauForm.tsx | 40 +- src/components/shared/DistrictSelect.tsx | 8 +- src/components/shared/ImageUpload.tsx | 12 + src/components/shared/StateSelect.tsx | 2 + src/env.mjs | 36 +- src/pages/api/s3-upload.ts | 4 +- src/pages/index.tsx | 2 +- sst.config.ts | 2 +- yarn.lock | 1036 ++++++++++++++++++++-- 13 files changed, 1187 insertions(+), 117 deletions(-) create mode 100644 kysely/kyselyschema.ts create mode 100644 src/components/shared/ImageUpload.tsx diff --git a/.env.example b/.env.example index 73ef702..683c259 100644 --- a/.env.example +++ b/.env.example @@ -20,10 +20,6 @@ DATABASE_URL="postgresql://postgres:@/?schema= NEXTAUTH_SECRET="" NEXTAUTH_URL="http://localhost:3000" -# Next Auth Discord Provider -DISCORD_CLIENT_ID="" -DISCORD_CLIENT_SECRET="" - # AWS S3 # I'm using https://next-s3-upload.codingvalue.com/ to upload images to S3, please follow tutorial to setup your own bucket, or you can reach out to me for bucket credentials S3_UPLOAD_KEY= diff --git a/kysely/kyselyschema.ts b/kysely/kyselyschema.ts new file mode 100644 index 0000000..282510f --- /dev/null +++ b/kysely/kyselyschema.ts @@ -0,0 +1,121 @@ +import type { ColumnType } from "kysely"; +export type Generated = T extends ColumnType + ? ColumnType + : ColumnType; +export type Timestamp = ColumnType; + +export type Account = { + id: string; + userId: string; + type: string; + provider: string; + providerAccountId: string; + refresh_token: string | null; + access_token: string | null; + expires_at: number | null; + token_type: string | null; + scope: string | null; + id_token: string | null; + session_state: string | null; +}; +export type Application = { + id: string; + name: string; + appKey: string; + appSecret: string; + createdAt: Generated; + updatedAt: Timestamp; + userId: string; +}; +export type District = { + id: string; + name: string; + unique_name: string; + state_id: string; +}; +export type Mall = { + id: string; + name: string; + label: Generated; + value: Generated; + district_id: string; + state_id: string; +}; +export type Qiblat = { + id: string; + surau_id: string; + latitude: number; + longitude: number; + degree: number; +}; +export type Rating = { + id: string; + rating: number; + review: string | null; + created_at: Generated; + surau_id: string; + user_id: string | null; +}; +export type Session = { + id: string; + sessionToken: string; + userId: string; + expires: Timestamp; +}; +export type State = { + id: string; + name: string; + unique_name: string; +}; +export type Surau = { + id: string; + name: string; + unique_name: string; + brief_direction: string | null; + is_approved: Generated; + is_approved_at: Timestamp | null; + created_at: Generated; + updated_at: Timestamp; + state_id: string; + district_id: string; + mall_id: string | null; + is_qiblat_certified: Generated; + is_solat_jumaat: Generated; + user_id: string | null; + application_id: string | null; +}; +export type SurauPhoto = { + id: string; + file_path: string; + caption: string | null; + created_at: Generated; + surau_id: string; + rating_id: string | null; +}; +export type User = { + id: string; + name: string | null; + email: string | null; + emailVerified: Timestamp | null; + image: string | null; + createdAt: Generated; +}; +export type VerificationToken = { + identifier: string; + token: string; + expires: Timestamp; +}; +export type DB = { + Account: Account; + Application: Application; + District: District; + Mall: Mall; + Qiblat: Qiblat; + Rating: Rating; + Session: Session; + State: State; + Surau: Surau; + SurauPhoto: SurauPhoto; + User: User; + VerificationToken: VerificationToken; +}; diff --git a/package.json b/package.json index 5292cb5..9cd40d6 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,12 @@ "private": true, "scripts": { "build": "next build", - "dev": "sst bind next dev", + "dev": "next dev", "postinstall": "prisma generate", "lint": "next lint", "start": "next start", "db-seed": "cross-env NODE_ENV=development prisma db seed", + "db-seed:local": "NODE_ENV=development dotenv -e .env.local -- prisma db seed", "update-district": "NODE_ENV=development tsx scripts/updateDistrict.ts", "update-district:staging": "NODE_ENV=development dotenv -e .env.local -- tsx scripts/updateDistrict.ts", "push:local": "dotenv -e .env.local -- prisma db push", @@ -42,6 +43,7 @@ "next-auth": "^4.19.0", "next-s3-upload": "^0.3.0", "nodemailer": "^6.9.3", + "prisma-kysely": "^1.5.0", "react": "18.2.0", "react-dom": "18.2.0", "react-dropzone": "^14.2.3", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5c7b87f..5501bfa 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -6,6 +6,12 @@ generator client { binaryTargets = ["native", "linux-arm64-openssl-1.0.x", "linux-musl-openssl-3.0.x"] } +generator kysely { + provider = "prisma-kysely" + output = "../kysely" + fileName = "kyselyschema.ts" +} + datasource db { provider = "postgresql" // NOTE: When using postgresql, mysql or sqlserver, uncomment the @db.Text annotations in model Account below @@ -15,12 +21,6 @@ datasource db { url = env("DATABASE_URL") } -model Example { - id String @id @default(cuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} - model Surau { id String @id @default(cuid()) name String @@ -43,6 +43,8 @@ model Surau { is_solat_jumaat Boolean @default(false) user_id String? user User? @relation(fields: [user_id], references: [id]) + application_id String? + application Application? @relation(fields: [application_id], references: [id]) } model Qiblat { @@ -127,6 +129,18 @@ model Account { @@unique([provider, providerAccountId]) } +model Application { + id String @id @default(cuid()) + name String + appKey String @unique + appSecret String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User @relation(fields: [userId], references: [id]) + userId String + Surau Surau[] +} + model Session { id String @id @default(cuid()) sessionToken String @unique @@ -136,16 +150,17 @@ model Session { } model User { - id String @id @default(cuid()) + id String @id @default(cuid()) name String? - email String? @unique + email String? @unique emailVerified DateTime? image String? accounts Account[] sessions Session[] Surau Surau[] Rating Rating[] - createdAt DateTime @default(now()) + Application Application[] + createdAt DateTime @default(now()) } model VerificationToken { diff --git a/src/components/AddSurauForm.tsx b/src/components/AddSurauForm.tsx index 6916f93..4f4529c 100644 --- a/src/components/AddSurauForm.tsx +++ b/src/components/AddSurauForm.tsx @@ -6,12 +6,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ import dynamic from "next/dynamic"; import type { FC } from "react"; -import { useEffect } from "react"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import Image from "next/image"; import { api } from "../utils/api"; import AlertModal from "./shared/AlertModal"; -import type { District } from "@prisma/client"; import { UploadButton } from "../utils/uploadthing"; // You need to import our styles for the button to look right. Best to import in the root /_app.tsx but this is fine import "@uploadthing/react/styles.css"; @@ -19,10 +17,6 @@ import StateSelect from "./shared/StateSelect"; import { generateCombination } from "../utils"; import DistrictSelect from "./shared/DistrictSelect"; -const Select = dynamic(() => import("react-select"), { - ssr: true, -}); - const AsyncCreatableSelect = dynamic( () => import("react-select/async-creatable"), { @@ -74,10 +68,15 @@ const AddSurauForm: FC = ({ setOpen }) => { const [qiblatDegree, setQiblatDegree] = useState(0); const [qiblatInfoError, setQiblatInfoError] = useState(""); + const Select = dynamic(() => import("react-select"), { + ssr: true, + }); + const mall = api.surau.getMallOnDistrict.useQuery({ district_id: choosenDistrict, state_id: choosenState, }); + const addSurau = api.surau.addSurau.useMutation(); const handleNegeriChange = (e: any) => { @@ -117,20 +116,6 @@ const AddSurauForm: FC = ({ setOpen }) => { setImagePreviews(images); }; - const filterMall = (inputValue: string) => { - if (!mall.data) return []; - return mall.data?.filter((i) => - i.value.toLowerCase().includes(inputValue.toLowerCase()) - ); - }; - - const promiseOptions = (inputValue: string) => - new Promise((resolve) => { - setTimeout(() => { - resolve(filterMall(inputValue)); - }, 1000); - }); - const handleSubmit = (e: React.MouseEvent) => { const qiblat = { latitude: latitude, @@ -189,6 +174,7 @@ const AddSurauForm: FC = ({ setOpen }) => { }); }; + return ( <> = ({ setOpen }) => { - + {choosenState ? ( ) : null} @@ -275,12 +262,13 @@ const AddSurauForm: FC = ({ setOpen }) => { - handleMallChange(e)} - loadOptions={promiseOptions} - cacheOptions - defaultOptions + options={mall.data} + getOptionLabel={(option: any) => option.name} + getOptionValue={(option: any) => option.id} + placeholder="Mall" /> diff --git a/src/components/shared/DistrictSelect.tsx b/src/components/shared/DistrictSelect.tsx index af4d52e..b6bc7b0 100644 --- a/src/components/shared/DistrictSelect.tsx +++ b/src/components/shared/DistrictSelect.tsx @@ -3,6 +3,7 @@ import dynamic from "next/dynamic"; import { api } from "../../utils/api"; import LoadingSpinner from "./LoadingSpinner"; +import { useEffect } from "react"; const Select = dynamic(() => import("react-select"), { ssr: true, @@ -19,10 +20,15 @@ const DistrictSelect: React.FC = ({ choosenState, label, }) => { - const { data, isLoading } = api.surau.getDistrict.useQuery({ + const { data, isLoading, refetch } = api.surau.getDistrict.useQuery({ id: choosenState, }); + useEffect(() => { + void refetch(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [choosenState]) + if (isLoading) return ; return (
diff --git a/src/components/shared/ImageUpload.tsx b/src/components/shared/ImageUpload.tsx new file mode 100644 index 0000000..0081574 --- /dev/null +++ b/src/components/shared/ImageUpload.tsx @@ -0,0 +1,12 @@ +const ImageUpload = () => { + return ( +
+ image upload here +
+ test +
+
+ ) +} + +export default ImageUpload; \ No newline at end of file diff --git a/src/components/shared/StateSelect.tsx b/src/components/shared/StateSelect.tsx index d2f80ba..014f334 100644 --- a/src/components/shared/StateSelect.tsx +++ b/src/components/shared/StateSelect.tsx @@ -10,6 +10,7 @@ const Select = dynamic(() => import("react-select"), { type StateSelectProps = { handleNegeriChange: (e: any) => void; + setChoosenDistrict: (e: any) => void; label: boolean; }; @@ -17,6 +18,7 @@ const StateSelect: React.FC = ({ handleNegeriChange, label, }) => { + const { data, isLoading } = api.surau.getState.useQuery(); if (isLoading) return ; return ( diff --git a/src/env.mjs b/src/env.mjs index 88de9d5..8ac9391 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -17,16 +17,16 @@ const server = z.object({ // Since NextAuth.js automatically uses the VERCEL_URL if present. (str) => process.env.VERCEL_URL ?? str, // VERCEL_URL doesn't include `https` so it cant be validated as a URL - process.env.VERCEL ? z.string().min(1) : z.string().url(), + process.env.VERCEL ? z.string().min(1) : z.string().url() ), // Add `.min(1) on ID and SECRET if you want to make sure they're not empty - DISCORD_CLIENT_ID: z.string(), - DISCORD_CLIENT_SECRET: z.string(), - APPLICATION_URL:z.string(), - MAIL_HOST:z.string(), - MAIL_PORT:z.string(), - MAIL_USERNAME:z.string(), - MAIL_PASSWORD:z.string(), + // DISCORD_CLIENT_ID: z.string(), + // DISCORD_CLIENT_SECRET: z.string(), + APPLICATION_URL: z.string(), + MAIL_HOST: z.string(), + MAIL_PORT: z.string(), + MAIL_USERNAME: z.string(), + MAIL_PASSWORD: z.string(), GOOGLE_CLIENT_ID: z.string(), GOOGLE_CLIENT_SECRET: z.string(), }); @@ -38,7 +38,7 @@ const server = z.object({ */ const client = z.object({ // NEXT_PUBLIC_CLIENTVAR: z.string().min(1), - NEXT_PUBLIC_CLOUDFRONT_URL: z.string().url(), + // NEXT_PUBLIC_CLOUDFRONT_URL: z.string().url(), }); /** @@ -51,13 +51,13 @@ const processEnv = { NODE_ENV: process.env.NODE_ENV, NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, NEXTAUTH_URL: process.env.NEXTAUTH_URL, - DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID, - DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET, - NEXT_PUBLIC_CLOUDFRONT_URL: process.env.NEXT_PUBLIC_CLOUDFRONT_URL, - MAIL_HOST:process.env.MAIL_HOST, - MAIL_PORT:process.env.MAIL_PORT, - MAIL_USERNAME:process.env.MAIL_USERNAME, - MAIL_PASSWORD:process.env.MAIL_PASSWORD, + // DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID, + // DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET, + // NEXT_PUBLIC_CLOUDFRONT_URL: process.env.NEXT_PUBLIC_CLOUDFRONT_URL, + MAIL_HOST: process.env.MAIL_HOST, + MAIL_PORT: process.env.MAIL_PORT, + MAIL_USERNAME: process.env.MAIL_USERNAME, + MAIL_PASSWORD: process.env.MAIL_PASSWORD, APPLICATION_URL: process.env.APPLICATION_URL, GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, @@ -82,7 +82,7 @@ if (!!process.env.SKIP_ENV_VALIDATION == false) { if (parsed.success === false) { console.error( "❌ Invalid environment variables:", - parsed.error.flatten().fieldErrors, + parsed.error.flatten().fieldErrors ); throw new Error("Invalid environment variables"); } @@ -98,7 +98,7 @@ if (!!process.env.SKIP_ENV_VALIDATION == false) { throw new Error( process.env.NODE_ENV === "production" ? "❌ Attempted to access a server-side environment variable on the client" - : `❌ Attempted to access server-side environment variable '${prop}' on the client`, + : `❌ Attempted to access server-side environment variable '${prop}' on the client` ); /* @ts-ignore - can't type this properly in jsdoc */ return target[prop]; diff --git a/src/pages/api/s3-upload.ts b/src/pages/api/s3-upload.ts index 65f069d..0bf5129 100644 --- a/src/pages/api/s3-upload.ts +++ b/src/pages/api/s3-upload.ts @@ -1 +1,3 @@ -export { APIRoute as default } from "next-s3-upload"; \ No newline at end of file +export const s3UploadHandler = () => { + console.log("test"); +}; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index dc49837..76d9e20 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -107,7 +107,7 @@ export default function Index() { > -
+