diff --git a/.prettierrc b/.prettierrc
index ab57dca..f9e575c 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -11,7 +11,9 @@
"arrowParens": "always",
"importOrder": [
"^@/components(.*)$",
+ "^@/types(.*)$",
"^@/lib(.*)$",
+ "^@/providers(.*)$",
"^@/styles(.*)$",
"^[./]"
],
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c05e736..98ca98f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4489,7 +4489,7 @@ snapshots:
debug: 4.3.6
enhanced-resolve: 5.17.1
eslint: 8.57.0
- eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
+ eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.0.1(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.6
@@ -4501,7 +4501,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
+ eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
dependencies:
debug: 3.2.7
optionalDependencies:
diff --git a/public/next.svg b/public/next.svg
deleted file mode 100644
index 5174b28..0000000
--- a/public/next.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/public/vercel.svg b/public/vercel.svg
deleted file mode 100644
index d2f8422..0000000
--- a/public/vercel.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/app/favicon.ico b/src/app/favicon.ico
index 718d6fe..e20a7a8 100644
Binary files a/src/app/favicon.ico and b/src/app/favicon.ico differ
diff --git a/src/app/form/[id]/done/page.tsx b/src/app/form/[id]/done/page.tsx
new file mode 100644
index 0000000..c87c00c
--- /dev/null
+++ b/src/app/form/[id]/done/page.tsx
@@ -0,0 +1,15 @@
+import { Box } from '@/components'
+
+export default function Page() {
+ return (
+
+
+
+ คำตอบของคุณถูกบันทึกแล้ว
+
+
+ ขอบคุณสำหรับคำตอบ
+
+
+ )
+}
diff --git a/src/app/form/[id]/layout.tsx b/src/app/form/[id]/layout.tsx
index fbf0c86..43c9f7f 100644
--- a/src/app/form/[id]/layout.tsx
+++ b/src/app/form/[id]/layout.tsx
@@ -1,14 +1,23 @@
-import FormProvider from '@/providers/form-provider'
+import { getFormSchema } from '@/lib/form/get-form-schema'
+
+import { FormSchemaProvider } from '@/providers/form-schema-provider'
+
+export async function generateMetadata({
+ params: { id },
+}: {
+ params: { id: string }
+}) {
+ const form = await getFormSchema(id)
+
+ return {
+ title: form.heading,
+ }
+}
export default async function FormLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
- return {children}
- return (
-
- {children}
-
- )
+ return {children}
}
diff --git a/src/app/form/[id]/page.tsx b/src/app/form/[id]/page.tsx
index a3d6dd8..622c98b 100644
--- a/src/app/form/[id]/page.tsx
+++ b/src/app/form/[id]/page.tsx
@@ -1,19 +1,21 @@
'use client'
-import { useForm } from '@/providers/form-provider'
+import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
import { Toaster, toast } from 'react-hot-toast'
-import { FormContainer } from '@/components/form/form-container'
-import { FormHeader } from '@/components/form/form-header'
-import { FormQuestion } from '@/components/form/form-question'
+import { Box } from '@/components'
+import { Field } from '@/components/form/field'
+
+import { useFormSchema } from '@/providers/form-schema-provider'
interface PageProps {
params: { id: string }
}
export default function Page({ params: { id } }: PageProps) {
- const { form, setID } = useForm()
+ const { formSchema, setID } = useFormSchema()
+ const router = useRouter()
useEffect(() => {
setID(id)
@@ -37,7 +39,8 @@ export default function Page({ params: { id } }: PageProps) {
toast.error(errorData.error)
return
}
- window.location.href = `${process.env.NEXT_PUBLIC_BASE_URL}/form/done`
+
+ router.push(`/form/${id}/done`)
}
const handleReset = (e: React.FormEvent) => {
@@ -47,19 +50,27 @@ export default function Page({ params: { id } }: PageProps) {
return (
-
-
+
+
+ {formSchema.heading}
+
+
+
+ {formSchema.subheading}
+
+
+
-
+
)
}
diff --git a/src/app/form/api/route.ts b/src/app/form/api/route.ts
index d9e04f5..2b58bec 100644
--- a/src/app/form/api/route.ts
+++ b/src/app/form/api/route.ts
@@ -1,6 +1,6 @@
import { checkIdParams } from '@/lib/form/check-form'
+import { getFormIds } from '@/lib/form/get-form-ids'
import { getFormSchema } from '@/lib/form/get-form-schema'
-import { getNocoID } from '@/lib/form/get-nocoID'
export async function GET(request: Request) {
// checking id
@@ -23,7 +23,7 @@ export async function POST(request: Request) {
const body = await request.json()
- const tableIdResponse = await getNocoID(id)
+ const tableIdResponse = await getFormIds(id)
if (tableIdResponse === null) {
return Response.json({ error: 'No matching form name' }, { status: 400 })
}
diff --git a/src/app/form/done/page.tsx b/src/app/form/done/page.tsx
deleted file mode 100644
index 6ca7e22..0000000
--- a/src/app/form/done/page.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { FormHeader } from '@/components/form/form-header'
-
-export default function Page() {
- return (
-
-
-
- )
-}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 5b80db8..6d1d642 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -16,8 +16,8 @@ const ibmPlexSansThai = IBM_Plex_Sans_Thai({
// TODO: Add your own metadata
export const metadata: Metadata = {
- title: 'Create Next App',
- description: 'Generated by create next app',
+ title: 'Intania Form',
+ description: 'Form wrapper for Chula Intania',
}
export default function RootLayout({
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 2315334..80ba33b 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,7 +1,3 @@
export default function Home() {
- return (
-
- Hello World!
-
- )
+ return Unauthorized
}
diff --git a/src/components/box.tsx b/src/components/box.tsx
new file mode 100644
index 0000000..9378f3e
--- /dev/null
+++ b/src/components/box.tsx
@@ -0,0 +1,11 @@
+interface BoxProps {
+ children: React.ReactNode
+}
+
+export const Box = ({ children }: BoxProps): JSX.Element => {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/src/components/checkbox.tsx b/src/components/checkbox.tsx
new file mode 100644
index 0000000..e17d242
--- /dev/null
+++ b/src/components/checkbox.tsx
@@ -0,0 +1,32 @@
+'use client'
+
+import toast from 'react-hot-toast'
+
+import type { FormColumn } from '@/types'
+
+interface CheckboxProps {
+ column: FormColumn
+}
+
+export const Checkbox = ({ column }: CheckboxProps): JSX.Element => {
+ return (
+
+
+
+ )
+}
diff --git a/src/components/form/form-question.tsx b/src/components/form/field.tsx
similarity index 67%
rename from src/components/form/form-question.tsx
rename to src/components/form/field.tsx
index 60a0273..03e831c 100644
--- a/src/components/form/form-question.tsx
+++ b/src/components/form/field.tsx
@@ -1,8 +1,8 @@
-import { FormColumn } from '@/types/form'
+import { FormComponent } from '@/components/form/form-component'
-import { getFormComponent } from '@/components/form/form-component'
+import type { FormColumn } from '@/types'
-export function FormQuestion({ column }: { column: FormColumn }) {
+export function Field({ column }: { column: FormColumn }) {
return (
@@ -14,7 +14,7 @@ export function FormQuestion({ column }: { column: FormColumn }) {
{column.description}
- {getFormComponent(column)}
+ {FormComponent(column)}
)
}
diff --git a/src/components/form/form-component.tsx b/src/components/form/form-component.tsx
index fa00227..bd59266 100644
--- a/src/components/form/form-component.tsx
+++ b/src/components/form/form-component.tsx
@@ -1,133 +1,30 @@
-import { FormColumn } from '@/types/form'
-import { UIDataType } from '@/types/ui-data'
-import React from 'react'
-import { toast } from 'react-hot-toast'
+import { Checkbox, Input, SingleSelect, Textarea } from '@/components'
-import { Input } from '@/components/input'
+import type { FormColumn } from '@/types'
-export const getFormComponent = (column: FormColumn): React.ReactNode => {
- if (!Object.values(UIDataType).includes(column.uidt)) {
- return (
-
- This system does not support {column.uidt}.
-
- )
- }
+export const FormComponent = (column: FormColumn): React.ReactNode => {
switch (column.uidt) {
case 'SingleLineText':
- return (
-
- )
+ return
case 'PhoneNumber':
return (
)
case 'Number':
return (
-
+
)
case 'Checkbox':
- return (
-
-
-
- )
+ return
case 'SingleSelect':
- return (
-
-
-
- จำเป็นต้องเลือก
-
-
- )
+ return
case 'LongText':
- return (
-
- )
+ return
default:
return (
diff --git a/src/components/form/form-container.tsx b/src/components/form/form-container.tsx
deleted file mode 100644
index a55d2b8..0000000
--- a/src/components/form/form-container.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { cn } from '@/lib/utils'
-
-export function FormContainer({
- children,
- className,
-}: {
- children: React.ReactNode
- className?: string
-}) {
- return (
-
- {children}
-
- )
-}
diff --git a/src/components/form/form-header.tsx b/src/components/form/form-header.tsx
deleted file mode 100644
index 1109077..0000000
--- a/src/components/form/form-header.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Form } from '@/types/form'
-
-import { FormContainer } from './form-container'
-
-export function FormHeader({ form }: { form: Form }) {
- return (
-
-
- {form.heading}
-
-
- {form.subheading}
-
- )
-}
diff --git a/src/components/form/index.ts b/src/components/form/index.ts
new file mode 100644
index 0000000..4b5722a
--- /dev/null
+++ b/src/components/form/index.ts
@@ -0,0 +1,2 @@
+export * from './form-component'
+export * from './field'
diff --git a/src/components/index.ts b/src/components/index.ts
new file mode 100644
index 0000000..4158a0d
--- /dev/null
+++ b/src/components/index.ts
@@ -0,0 +1,6 @@
+export * from './box'
+export * from './form'
+export * from './checkbox'
+export * from './input'
+export * from './single-select'
+export * from './textarea'
diff --git a/src/components/single-select.tsx b/src/components/single-select.tsx
new file mode 100644
index 0000000..bf78180
--- /dev/null
+++ b/src/components/single-select.tsx
@@ -0,0 +1,37 @@
+import toast from 'react-hot-toast'
+
+import type { FormColumn } from '@/types'
+
+interface SingleSelectProps {
+ column: FormColumn
+}
+
+export const SingleSelect = ({ column }: SingleSelectProps): JSX.Element => {
+ return (
+
+
+
+ จำเป็นต้องเลือก
+
+
+ )
+}
diff --git a/src/components/textarea.tsx b/src/components/textarea.tsx
new file mode 100644
index 0000000..f2fdf0c
--- /dev/null
+++ b/src/components/textarea.tsx
@@ -0,0 +1,28 @@
+'use client'
+
+import toast from 'react-hot-toast'
+
+import type { FormColumn } from '@/types'
+
+interface TextareaProps {
+ column: FormColumn
+}
+
+export const Textarea = ({ column }: TextareaProps) => {
+ return (
+
+ )
+}
diff --git a/src/lib/fetcher.ts b/src/lib/fetcher.ts
deleted file mode 100644
index 868d442..0000000
--- a/src/lib/fetcher.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-interface IDMappingResponse {
- Id: number
- FormViewID: string
- TableID: string
-}
-
-export const getNocoID = async (
- name: string
-): Promise => {
- const id = await getIdByFormName(name)
- if (id === null) {
- return null
- }
-
- const response = await fetch(
- `${process.env.NOCODB_BASE_URL}/api/v2/tables/${process.env.ID_MAPPING_TABLE_ID}/records/${id}`,
- {
- headers: {
- 'xc-token': process.env.NOCODB_XC_TOKEN ?? '',
- },
- next: { revalidate: 60 },
- }
- )
- const data = await response.json()
- return data
-}
-
-const getIdByFormName = async (name: string) => {
- const response = await fetch(
- `${process.env.NOCODB_BASE_URL}/api/v2/tables/${process.env.ID_MAPPING_TABLE_ID}/records/`,
- {
- headers: {
- 'xc-token': process.env.NOCODB_XC_TOKEN ?? '',
- },
- next: { revalidate: 60 },
- }
- )
- const allForm = (await response.json()).list
-
- const formIdData = allForm.find((item: { CustomId: string }) => {
- if (item.CustomId === name) {
- return true
- }
- })
-
- if (formIdData === undefined) {
- return null
- }
- return formIdData.Id
-}
diff --git a/src/lib/form/check-form.ts b/src/lib/form/check-form.ts
index f8801e9..3875aab 100644
--- a/src/lib/form/check-form.ts
+++ b/src/lib/form/check-form.ts
@@ -1,8 +1,4 @@
export const checkIdParams = (request: Request) => {
const { searchParams } = new URL(request.url)
- const id = searchParams.get('id')
- if (!id) {
- return null
- }
- return id
+ return searchParams.get('id')
}
diff --git a/src/lib/form/get-column-detail.ts b/src/lib/form/get-column-detail.ts
index c7ccabb..5e876f3 100644
--- a/src/lib/form/get-column-detail.ts
+++ b/src/lib/form/get-column-detail.ts
@@ -1,13 +1,8 @@
-import { UIDataType } from '@/types/ui-data'
+import type { FormColumn } from '@/types'
export const getColumnDetail = async (
columnID: string
-): Promise<{
- label: string
- uidt: keyof typeof UIDataType
- columnName: string
- colOptions?: string[]
-}> => {
+): Promise> => {
const response = await fetch(
`${process.env.NOCODB_BASE_URL}/api/v2/meta/columns/${columnID}`,
{
@@ -20,11 +15,15 @@ export const getColumnDetail = async (
const data = await response.json()
return {
+ id: data.id,
label: data.title,
uidt: data.uidt,
- columnName: data.column_name,
- colOptions: data.colOptions?.options.map(
- (option: { title: string }) => option.title
+ name: data.column_name,
+ options: data.colOptions?.options.map(
+ (option: { id: string; title: string }) => ({
+ id: option.id,
+ title: option.title,
+ })
),
}
}
diff --git a/src/lib/form/get-form-ids.ts b/src/lib/form/get-form-ids.ts
new file mode 100644
index 0000000..469ad6a
--- /dev/null
+++ b/src/lib/form/get-form-ids.ts
@@ -0,0 +1,26 @@
+interface FormIds {
+ Id: string
+ CustomId: string
+ TableID: string
+ FormViewID: string
+}
+
+export const getFormIds = async (CustomId: string): Promise => {
+ const response = await fetch(
+ `${process.env.NOCODB_BASE_URL}/api/v2/tables/${process.env.ID_MAPPING_TABLE_ID}/records`,
+ {
+ headers: {
+ 'xc-token': process.env.NOCODB_XC_TOKEN ?? '',
+ },
+ next: { revalidate: 60 },
+ }
+ )
+ const data = await response.json()
+ const allForm = data.list as FormIds[]
+
+ const formIdData = allForm.find(
+ (item: { CustomId: string }) => item.CustomId === CustomId
+ )
+
+ return formIdData ?? null
+}
diff --git a/src/lib/form/get-form-schema.ts b/src/lib/form/get-form-schema.ts
index 5c8f702..2b3a085 100644
--- a/src/lib/form/get-form-schema.ts
+++ b/src/lib/form/get-form-schema.ts
@@ -1,12 +1,12 @@
-import { Form, FormColumn } from '@/types/form'
+import type { Form } from '@/types/form'
import { getColumnDetail } from './get-column-detail'
-import { getNocoID } from './get-nocoID'
+import { getFormIds } from './get-form-ids'
-export const getFormSchema = async (id: string): Promise