parent
359b89b627
commit
59eb4b2169
18 changed files with 1143 additions and 245 deletions
@ -0,0 +1 @@ |
||||
{"type": "commonjs"} |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,6 @@ |
||||
module.exports = { |
||||
plugins: { |
||||
tailwindcss: {}, |
||||
autoprefixer: {}, |
||||
}, |
||||
} |
||||
@ -1,7 +1,7 @@ |
||||
import * as React from 'react' |
||||
import Link from 'next/link' |
||||
|
||||
const Header = ({ pathname }) => ( |
||||
const Header = ({ pathname }: { pathname?: string }) => ( |
||||
<header> |
||||
<Link href="/"> |
||||
<a className={pathname === '/' ? 'is-active' : ''}>Home</a> |
||||
@ -0,0 +1,5 @@ |
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@ -1,3 +1,7 @@ |
||||
module.exports = { |
||||
distDir: '../.next', |
||||
esmExternals: false, |
||||
experimental: { |
||||
esmExternals: false |
||||
}, |
||||
} |
||||
|
||||
@ -0,0 +1,36 @@ |
||||
import '../styles/globals.css' |
||||
import { getFirestore } from 'firebase/firestore'; |
||||
import { FirebaseAppProvider, FirestoreProvider, useFirebaseApp } from 'reactfire'; |
||||
|
||||
// Your web app's Firebase configuration
|
||||
const firebaseConfig = { |
||||
apiKey: "AIzaSyBdgSlMbnKwFnCxKu3tMAp4tpCQpG5V1uw", |
||||
authDomain: "uc-21006-backend.firebaseapp.com", |
||||
projectId: "uc-21006-backend", |
||||
storageBucket: "uc-21006-backend.appspot.com", |
||||
messagingSenderId: "667264331891", |
||||
appId: "1:667264331891:web:8ab0331441423cb883fa06" |
||||
}; |
||||
|
||||
function FirebaseSDKProviders({ children }) { |
||||
const app = useFirebaseApp() |
||||
const firestore = getFirestore(app) |
||||
|
||||
return ( |
||||
<FirestoreProvider sdk={firestore}> |
||||
{children} |
||||
</FirestoreProvider> |
||||
) |
||||
} |
||||
|
||||
function App({ Component, pageProps }) { |
||||
return ( |
||||
<FirebaseAppProvider firebaseConfig={firebaseConfig}> |
||||
<FirebaseSDKProviders> |
||||
<Component {...pageProps} /> |
||||
</FirebaseSDKProviders> |
||||
</FirebaseAppProvider> |
||||
) |
||||
} |
||||
|
||||
export default App |
||||
@ -0,0 +1,22 @@ |
||||
import type { NextApiRequest, NextApiResponse } from 'next' |
||||
import db from '../../utils/db'; |
||||
import { database } from 'firebase-admin'; |
||||
|
||||
export default async function handler( |
||||
req: NextApiRequest, |
||||
res: NextApiResponse |
||||
) { |
||||
try { |
||||
const { slug } = req.body; |
||||
const entries = await db.collection('questionnaire').get(); |
||||
const entriesData = entries.docs.map(entry => entry.data()); |
||||
|
||||
const { id } = await db.collection('questionnaire').add({ |
||||
...req.body, |
||||
created: new Date().toISOString(), |
||||
}); |
||||
res.status(200).json({ id }); |
||||
} catch (e) { |
||||
res.status(400).end(); |
||||
} |
||||
} |
||||
@ -0,0 +1,8 @@ |
||||
import type { NextApiRequest, NextApiResponse } from 'next' |
||||
|
||||
export default async function handler( |
||||
req: NextApiRequest, |
||||
res: NextApiResponse |
||||
) { |
||||
res.status(200).json({ name: 'John Doe' }) |
||||
} |
||||
@ -1,9 +1,74 @@ |
||||
import { useRef } from 'react'; |
||||
import App from '../components/App' |
||||
|
||||
import { collection, query, orderBy } from '@firebase/firestore'; |
||||
import { useFirestore, useFirestoreCollectionData } from 'reactfire'; |
||||
|
||||
export default function Home() { |
||||
const firestore = useFirestore(); |
||||
const questionnaireCollection = collection(firestore, 'questionnaire'); |
||||
const questionnaireQuery = query(questionnaireCollection, orderBy('created', 'desc')); |
||||
|
||||
const { status, data: questionnaire } = useFirestoreCollectionData(questionnaireQuery, { |
||||
idField: 'id', // this field will be added to the object created from each document |
||||
}); |
||||
|
||||
const Q1Ref = useRef(); |
||||
|
||||
async function handleSubmit(event) { |
||||
event.preventDefault(); |
||||
|
||||
let body = JSON.stringify({ |
||||
Q1: Q1Ref.current.value, |
||||
}); |
||||
try { |
||||
let r = await fetch("/api/addQuestionnaire", { |
||||
method: 'POST', |
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
'Content-Length': body.length.toString(), |
||||
}, |
||||
body: body, |
||||
}); |
||||
let data = await r.json(); |
||||
console.log(data); |
||||
} |
||||
catch (e) { |
||||
console.error(e); |
||||
} |
||||
console.log(Q1Ref.current.value); |
||||
} |
||||
|
||||
return ( |
||||
<App> |
||||
<p>Index Page</p> |
||||
<div className="artboard phone-1 rounded-lg border-0 flex flex-col p-2 gap-4"> |
||||
<form className="form-control w-full max-w-xs gap-2" onSubmit={handleSubmit}> |
||||
<label className="label"> |
||||
<span className="label-text">你最喜歡的科幻/奇幻作品是哪一個?</span> |
||||
{/* <span class="label-text-alt">Alt label</span> */} |
||||
</label> |
||||
{/* <select className="select select-bordered" value="Pick one" onChange={handleChange}> */} |
||||
<select className="select select-bordered" ref={Q1Ref}> |
||||
<option disabled selected>Pick one</option> |
||||
<option>Star Wars</option> |
||||
<option>Harry Potter</option> |
||||
<option>Lord of the Rings</option> |
||||
<option>Planet of the Apes</option> |
||||
<option>Star Trek</option> |
||||
</select> |
||||
<input className="btn" type="submit" value="Submit" /> |
||||
{/* <label class="label"> |
||||
<span class="label-text-alt">Alt label</span> |
||||
<span class="label-text-alt">Alt label</span> |
||||
</label> */} |
||||
</form> |
||||
{/* <button className="btn" onClick={() => console.log("test")}>Button</button> */} |
||||
{ |
||||
status == 'success' && questionnaire.map(q => ( |
||||
<div key={q.id} className=' '>{q.Q1}</div> |
||||
)) |
||||
} |
||||
</div> |
||||
</App> |
||||
) |
||||
} |
||||
|
||||
@ -0,0 +1,3 @@ |
||||
@tailwind base; |
||||
@tailwind components; |
||||
@tailwind utilities; |
||||
@ -0,0 +1,30 @@ |
||||
{ |
||||
"compilerOptions": { |
||||
"target": "es5", |
||||
"lib": [ |
||||
"dom", |
||||
"dom.iterable", |
||||
"esnext" |
||||
], |
||||
"allowJs": true, |
||||
"skipLibCheck": true, |
||||
"strict": false, |
||||
"forceConsistentCasingInFileNames": true, |
||||
"noEmit": true, |
||||
"incremental": true, |
||||
"esModuleInterop": true, |
||||
"module": "esnext", |
||||
"moduleResolution": "node", |
||||
"resolveJsonModule": true, |
||||
"isolatedModules": true, |
||||
"jsx": "preserve" |
||||
}, |
||||
"include": [ |
||||
"next-env.d.ts", |
||||
"**/*.ts", |
||||
"**/*.tsx" |
||||
], |
||||
"exclude": [ |
||||
"node_modules" |
||||
] |
||||
} |
||||
@ -0,0 +1,14 @@ |
||||
import admin from 'firebase-admin'; |
||||
import serviceAccount from './serviceAccountKey.json'; |
||||
|
||||
if (!admin.apps.length) { |
||||
try { |
||||
admin.initializeApp({ |
||||
credential: admin.credential.cert(serviceAccount), |
||||
// databaseURL: "YOUR_DB_URL"
|
||||
}); |
||||
} catch (error) { |
||||
console.log('Firebase admin initialization error', error.stack); |
||||
} |
||||
} |
||||
export default admin.firestore(); |
||||
@ -0,0 +1,12 @@ |
||||
{ |
||||
"type": "service_account", |
||||
"project_id": "uc-21006-backend", |
||||
"private_key_id": "82cf89939b88a851b1687b7ec910945044889fcc", |
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCQUKqzUJ4Q4NqS\nakcXGenyPOqj8P4yurfzGW3E0O/a00TsNwdpZQ4RTuKKA17cHJq3/l5qyuoYqo/V\nQUtck9VDTyJBxd4wYJBlywpwv+pmVdTDLZ3qVfsG/I7FLOKqfaml0V5vRan1m3Zw\nnJAcTLHM9kt1Wr+q2Me54Q8EBsyUzKyxYwI3WCsCcuLj9l5EfFHymGLT/Yg2stQ3\nsUNzBN4g7C1JiVXxSfvDgFE1vhYfkv+NEhx32rOis7DI0vy25LbuGFksNmFbrp/0\nzJthhRh7nkGdQs8erdH79qcb5VVIqGG+98GOmv774bNu3qnJdn4j3NjAkAGeP0gL\n6RigvmsVAgMBAAECggEAALD1Ic+nf0Ibu1xZUkbqIpagSi68gbDJ/gtHl2kcD+lD\nVJ06Iq3rJOBxZeLs+U0cUbKRZKlf+MRGMhhMmxwYWJde5dE1Q7I85KRKPMjtFsTw\n11BOWWv+vEVggg1zn2WdyFDogSk1/RqKWA4a1SZp+/hXfi+W//rEM5f/X/XV1NeH\nj+xIqj8h5a1TriOlAUuy4yppXkSatan6hwQQqFUterzspn+ctmZ0nGHjSa+RsS3h\nG9eUMoOVfILkY8mGzyee4GDdKUchALmZ3OsVr1R6yd3sdureOOuRiicYKthggbYl\n5em3LnTEvYazf5hy5wI0ie+xZV5OHWICXX/57AjLlQKBgQDF4Hd2x05O53vzaDsM\nODxb5WBipeND5I1qlI6J59J7q3CaSOBgPa6x1r9RF+ISzPyKJftMMINF9Pk4Lw/n\nB7di12MqjmI8IV3YjbQAD9+RqWIN1ERh76+Gkqg9+W0ClhtK9DtznXWASuoqo2U/\n9LtVvmaNd+J4A/OHN2KSc+8HZwKBgQC6tJOU8ImOo0VOExR3KnF8DmIx5Eh5L2g0\nHSEQQgIgGYSsT0FKW4qZPKOdMWZ97i7f8cKiYqeSX6YD8iEM+S/40zsnrh/7iGjp\n0wKdWmi16b/TBAiLKO+vWtnmjU3s6ElZK5QxVTMy1GptyfXbQqotsWnKTqFbAG6B\n15VN5TNYIwKBgHMFUovxuHw3JJ7NdJ1axwMn5woQoXViki1k4yIYZgpLEm4sdHid\nAkIPsS/jMR96lkV7ZILaJERy7LcS7CyAGMJUrykakNGhF5r8a6gpkexqyDt/qqw/\nFgmkkDVOGmaJeJ3uL+y5l4aWhV15ky5FBOwHfDc5e6QFr/ZmZF77EvN7AoGASKYN\nKw4xqFP1mryn4Pqd7/S01s8KOEVvGaAgBnB43T6wtk+ciy91jczfqUHYrLWqfa9X\n2dHjfHxFYBGuNJsdxIeE5BrIDRr2H83gnZPZXLeY0aYnIOcL5MLIOQLQyJdWOyFO\n56dMZcHrq87DIM8e4uq+zF6uQHe5iEJ3sTi3MtsCgYBYf91+Ff+kU4YBp+mQJX9u\nqVWdjVUxFku+4/ZAWvoOsoDKLSKN7gOLBY0e6nlc4j09jzNgTZ24TPMS4XGocpWm\nLazqyzCKFLViMS0rZfcPZVPh3I9/IFwkZPMxklKpfZLHhw8xiXH+iw486nRl4FT/\nKj9ejmo6M4jOaNFAV0oi5w==\n-----END PRIVATE KEY-----\n", |
||||
"client_email": "firebase-adminsdk-6mr45@uc-21006-backend.iam.gserviceaccount.com", |
||||
"client_id": "116964042143658711653", |
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth", |
||||
"token_uri": "https://oauth2.googleapis.com/token", |
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", |
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-6mr45%40uc-21006-backend.iam.gserviceaccount.com" |
||||
} |
||||
@ -0,0 +1,10 @@ |
||||
module.exports = { |
||||
content: [ |
||||
"./src/pages/**/*.{js,ts,jsx,tsx}", |
||||
"./src/components/**/*.{js,ts,jsx,tsx}", |
||||
], |
||||
theme: { |
||||
extend: {}, |
||||
}, |
||||
plugins: [require("daisyui")] |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue