From 81eba2ef2ffda4d2393751bcac867cdae5532f01 Mon Sep 17 00:00:00 2001 From: Obadja Ris Date: Tue, 15 Sep 2020 18:37:42 +0200 Subject: [PATCH] Commited! --- app/choices/mutations/createChoice.ts | 16 + app/choices/mutations/deleteChoice.ts | 17 + app/choices/mutations/updateChoice.ts | 18 + app/choices/queries/getChoice.ts | 21 + app/choices/queries/getChoices.ts | 35 ++ app/layouts/style.css | 0 app/questions/components/QuestionForm.tsx | 26 ++ app/questions/mutations/createQuestion.ts | 16 + app/questions/mutations/deleteQuestion.ts | 10 + app/questions/mutations/updateQuestion.ts | 18 + .../pages/questions/[questionId].tsx | 79 ++++ .../pages/questions/[questionId]/edit.tsx | 63 +++ app/questions/pages/questions/index.tsx | 80 ++++ app/questions/pages/questions/new.tsx | 55 +++ app/questions/queries/getQuestion.ts | 16 + app/questions/queries/getQuestions.ts | 35 ++ blitzjs.com | 1 + .../README.md | 87 ++++ .../schema.prisma | 38 ++ .../steps.json | 398 ++++++++++++++++++ .../20200912172104-init-db/README.md | 69 +++ .../20200912172104-init-db/schema.prisma | 56 +++ .../20200912172104-init-db/steps.json | 305 ++++++++++++++ db/migrations/migrate.lock | 4 + db/schema.prisma | 18 + package-lock.json | 242 ++++++++++- package.json | 7 +- 27 files changed, 1722 insertions(+), 8 deletions(-) create mode 100644 app/choices/mutations/createChoice.ts create mode 100644 app/choices/mutations/deleteChoice.ts create mode 100644 app/choices/mutations/updateChoice.ts create mode 100644 app/choices/queries/getChoice.ts create mode 100644 app/choices/queries/getChoices.ts create mode 100644 app/layouts/style.css create mode 100644 app/questions/components/QuestionForm.tsx create mode 100644 app/questions/mutations/createQuestion.ts create mode 100644 app/questions/mutations/deleteQuestion.ts create mode 100644 app/questions/mutations/updateQuestion.ts create mode 100644 app/questions/pages/questions/[questionId].tsx create mode 100644 app/questions/pages/questions/[questionId]/edit.tsx create mode 100644 app/questions/pages/questions/index.tsx create mode 100644 app/questions/pages/questions/new.tsx create mode 100644 app/questions/queries/getQuestion.ts create mode 100644 app/questions/queries/getQuestions.ts create mode 160000 blitzjs.com create mode 100644 db/migrations/20200912171755-initial-migration/README.md create mode 100644 db/migrations/20200912171755-initial-migration/schema.prisma create mode 100644 db/migrations/20200912171755-initial-migration/steps.json create mode 100644 db/migrations/20200912172104-init-db/README.md create mode 100644 db/migrations/20200912172104-init-db/schema.prisma create mode 100644 db/migrations/20200912172104-init-db/steps.json create mode 100644 db/migrations/migrate.lock diff --git a/app/choices/mutations/createChoice.ts b/app/choices/mutations/createChoice.ts new file mode 100644 index 0000000..83e37a7 --- /dev/null +++ b/app/choices/mutations/createChoice.ts @@ -0,0 +1,16 @@ +import { SessionContext } from "blitz" +import db, { ChoiceCreateArgs } from "db" + +type CreateChoiceInput = { + data: ChoiceCreateArgs["data"] +} +export default async function createChoice( + { data }: CreateChoiceInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const choice = await db.choice.create({ data }) + + return choice +} diff --git a/app/choices/mutations/deleteChoice.ts b/app/choices/mutations/deleteChoice.ts new file mode 100644 index 0000000..39d692a --- /dev/null +++ b/app/choices/mutations/deleteChoice.ts @@ -0,0 +1,17 @@ +import { SessionContext } from "blitz" +import db, { ChoiceDeleteArgs } from "db" + +type DeleteChoiceInput = { + where: ChoiceDeleteArgs["where"] +} + +export default async function deleteChoice( + { where }: DeleteChoiceInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const choice = await db.choice.delete({ where }) + + return choice +} diff --git a/app/choices/mutations/updateChoice.ts b/app/choices/mutations/updateChoice.ts new file mode 100644 index 0000000..376d510 --- /dev/null +++ b/app/choices/mutations/updateChoice.ts @@ -0,0 +1,18 @@ +import { SessionContext } from "blitz" +import db, { ChoiceUpdateArgs } from "db" + +type UpdateChoiceInput = { + where: ChoiceUpdateArgs["where"] + data: ChoiceUpdateArgs["data"] +} + +export default async function updateChoice( + { where, data }: UpdateChoiceInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const choice = await db.choice.update({ where, data }) + + return choice +} diff --git a/app/choices/queries/getChoice.ts b/app/choices/queries/getChoice.ts new file mode 100644 index 0000000..4218045 --- /dev/null +++ b/app/choices/queries/getChoice.ts @@ -0,0 +1,21 @@ +import { NotFoundError, SessionContext } from "blitz" +import db, { FindOneChoiceArgs } from "db" + +type GetChoiceInput = { + where: FindOneChoiceArgs["where"] + // Only available if a model relationship exists + // include?: FindOneChoiceArgs['include'] +} + +export default async function getChoice( + { where /* include */ }: GetChoiceInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const choice = await db.choice.findOne({ where }) + + if (!choice) throw new NotFoundError() + + return choice +} diff --git a/app/choices/queries/getChoices.ts b/app/choices/queries/getChoices.ts new file mode 100644 index 0000000..d2dab78 --- /dev/null +++ b/app/choices/queries/getChoices.ts @@ -0,0 +1,35 @@ +import { SessionContext } from "blitz" +import db, { FindManyChoiceArgs } from "db" + +type GetChoicesInput = { + where?: FindManyChoiceArgs["where"] + orderBy?: FindManyChoiceArgs["orderBy"] + skip?: FindManyChoiceArgs["skip"] + take?: FindManyChoiceArgs["take"] + // Only available if a model relationship exists + // include?: FindManyChoiceArgs['include'] +} + +export default async function getChoices( + { where, orderBy, skip = 0, take }: GetChoicesInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const choices = await db.choice.findMany({ + where, + orderBy, + take, + skip, + }) + + const count = await db.choice.count() + const hasMore = typeof take === "number" ? skip + take < count : false + const nextPage = hasMore ? { take, skip: skip + take! } : null + + return { + choices, + nextPage, + hasMore, + } +} diff --git a/app/layouts/style.css b/app/layouts/style.css new file mode 100644 index 0000000..e69de29 diff --git a/app/questions/components/QuestionForm.tsx b/app/questions/components/QuestionForm.tsx new file mode 100644 index 0000000..7b4a320 --- /dev/null +++ b/app/questions/components/QuestionForm.tsx @@ -0,0 +1,26 @@ +import React from "react" + +type QuestionFormProps = { + initialValues: any + onSubmit: React.FormEventHandler +} + +const QuestionForm = ({ initialValues, onSubmit }: QuestionFormProps) => { + return ( +
{ + event.preventDefault() + onSubmit(event) + }} + > + + + + +
{JSON.stringify(initialValues)}
+ +
+ ) +} + +export default QuestionForm diff --git a/app/questions/mutations/createQuestion.ts b/app/questions/mutations/createQuestion.ts new file mode 100644 index 0000000..fce9c14 --- /dev/null +++ b/app/questions/mutations/createQuestion.ts @@ -0,0 +1,16 @@ +import { SessionContext } from "blitz" +import db, { QuestionCreateArgs } from "db" + +type CreateQuestionInput = { + data: QuestionCreateArgs["data"] +} +export default async function createQuestion( + { data }: CreateQuestionInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const question = await db.question.create({ data }) + + return question +} diff --git a/app/questions/mutations/deleteQuestion.ts b/app/questions/mutations/deleteQuestion.ts new file mode 100644 index 0000000..0fb65fc --- /dev/null +++ b/app/questions/mutations/deleteQuestion.ts @@ -0,0 +1,10 @@ +import db, { FindManyQuestionArgs } from "db" +export default async function deleteQuestion( + { where }: DeleteQuestionInput, + ctx: Record = {} +) { + // TODO: remove once Prisma supports cascading deletes + await db.choice.deleteMany({ where: { question: { id: where.id } } }) + const question = await db.question.delete({ where }) + return question +} diff --git a/app/questions/mutations/updateQuestion.ts b/app/questions/mutations/updateQuestion.ts new file mode 100644 index 0000000..de31c85 --- /dev/null +++ b/app/questions/mutations/updateQuestion.ts @@ -0,0 +1,18 @@ +import { SessionContext } from "blitz" +import db, { QuestionUpdateArgs } from "db" + +type UpdateQuestionInput = { + where: QuestionUpdateArgs["where"] + data: QuestionUpdateArgs["data"] +} + +export default async function updateQuestion( + { where, data }: UpdateQuestionInput, + ctx: { session?: SessionContext } = {} +) { + ctx.session!.authorize() + + const question = await db.question.update({ where, data }) + + return question +} diff --git a/app/questions/pages/questions/[questionId].tsx b/app/questions/pages/questions/[questionId].tsx new file mode 100644 index 0000000..933d41f --- /dev/null +++ b/app/questions/pages/questions/[questionId].tsx @@ -0,0 +1,79 @@ +import React, { Suspense } from "react" +import Layout from "app/layouts/Layout" +import { Head, Link, useRouter, useQuery, useParam, BlitzPage } from "blitz" +import getQuestion from "app/questions/queries/getQuestion" +import deleteQuestion from "app/questions/mutations/deleteQuestion" +import updateChoice from "app/choices/mutations/updateChoice" + +export const Question = () => { + const router = useRouter() + const questionId = useParam("questionId", "number") + const [question, { refetch }] = useQuery(getQuestion, { where: { id: questionId } }) + const handleVote = async (id, votes) => { + try { + const updated = await updateChoice({ + where: { id }, + data: { votes: votes + 1 }, + }) + refetch() + } catch (error) { + alert("Error creating question " + JSON.stringify(error, null, 2)) + } + } + + return ( +
+

{question.text}

+
    + {question.choices.map((choice) => ( +
  • + {choice.text} - {choice.votes} votes + +
  • + ))} +
+ + + Edit + + + +
+ ) +} + +const ShowQuestionPage: BlitzPage = () => { + return ( +
+ + Question + + +
+

+ + Questions + +

+ + Loading...
}> + + + + + ) +} + +ShowQuestionPage.getLayout = (page) => {page} + +export default ShowQuestionPage diff --git a/app/questions/pages/questions/[questionId]/edit.tsx b/app/questions/pages/questions/[questionId]/edit.tsx new file mode 100644 index 0000000..a857447 --- /dev/null +++ b/app/questions/pages/questions/[questionId]/edit.tsx @@ -0,0 +1,63 @@ +import React, { Suspense } from "react" +import Layout from "app/layouts/Layout" +import { Head, Link, useRouter, useQuery, useParam, BlitzPage } from "blitz" +import getQuestion from "app/questions/queries/getQuestion" +import updateQuestion from "app/questions/mutations/updateQuestion" +import QuestionForm from "app/questions/components/QuestionForm" + +export const EditQuestion = () => { + const router = useRouter() + const questionId = useParam("questionId", "number") + const [question, { mutate }] = useQuery(getQuestion, { where: { id: questionId } }) + + return ( +
+

Edit Question {question.id}

+
{JSON.stringify(question)}
+ + { + try { + const updated = await updateQuestion({ + where: { id: question.id }, + data: { text: "Do you really love Blitz?" }, + }) + mutate(updated) + alert("Success!" + JSON.stringify(updated)) + router.push("/questions/[questionId]", `/questions/${updated.id}`) + } catch (error) { + console.log(error) + alert("Error creating question " + JSON.stringify(error, null, 2)) + } + }} + /> +
+ ) +} + +const EditQuestionPage: BlitzPage = () => { + return ( +
+ + Edit Question + + +
+ Loading...
}> + + + +

+ + Questions + +

+ + + ) +} + +EditQuestionPage.getLayout = (page) => {page} + +export default EditQuestionPage diff --git a/app/questions/pages/questions/index.tsx b/app/questions/pages/questions/index.tsx new file mode 100644 index 0000000..3a50b13 --- /dev/null +++ b/app/questions/pages/questions/index.tsx @@ -0,0 +1,80 @@ +import React, { Suspense } from "react" +import Layout from "app/layouts/Layout" +import { Head, Link, usePaginatedQuery, useRouter, BlitzPage } from "blitz" +import getQuestions from "app/questions/queries/getQuestions" +import updateChoice from "app/choices/mutations/updateChoice" + +const ITEMS_PER_PAGE = 100 + +export const QuestionsList = () => { + return ( +
+
    + {questions.map((question) => ( +
  • + + {question.text} + +
      + {question.choices.map((choice) => ( +
    • + {choice.text} - {choice.votes} votes +
    • + ))} +
    +
  • + ))} +
+
+ ) +} + +export const ButtonCreator = () => { + const router = useRouter() + const page = Number(router.query.page) || 0 + const [{ questions, hasMore }] = usePaginatedQuery(getQuestions, { + orderBy: { id: "asc" }, + skip: ITEMS_PER_PAGE * page, + take: ITEMS_PER_PAGE, + }) + const goToPreviousPage = () => router.push({ query: { page: page - 1 } }) + const goToNextPage = () => router.push({ query: { page: page + 1 } }) + return ( +
+ + +
+ ) +} + +const QuestionsPage: BlitzPage = () => { + return ( +
+ + Questions + + +
+

Questions

+ +

+ + Create Question + +

+ + Loading...
}> + + + + + ) +} + +QuestionsPage.getLayout = (page) => {page} + +export default QuestionsPage diff --git a/app/questions/pages/questions/new.tsx b/app/questions/pages/questions/new.tsx new file mode 100644 index 0000000..7a936e0 --- /dev/null +++ b/app/questions/pages/questions/new.tsx @@ -0,0 +1,55 @@ +import React from "react" +import Layout from "app/layouts/Layout" +import { Head, Link, useRouter, BlitzPage } from "blitz" +import createQuestion from "app/questions/mutations/createQuestion" +import QuestionForm from "app/questions/components/QuestionForm" + +const NewQuestionPage: BlitzPage = () => { + const router = useRouter() + + return ( +
+ + New Question + + +
+

Create New Question

+ + { + try { + const question = await createQuestion({ + data: { + text: event.target[0].value, + choices: { + create: [ + { text: event.target[1].value }, + { text: event.target[2].value }, + { text: event.target[3].value }, + ], + }, + }, + }) + alert("Success!" + JSON.stringify(question)) + router.push("/questions/[questionId]", `/questions/${question.id}`) + } catch (error) { + alert("Error creating question " + JSON.stringify(error, null, 2)) + } + }} + /> + +

+ + Questions + +

+
+
+ ) +} + +NewQuestionPage.getLayout = (page) => {page} + +export default NewQuestionPage diff --git a/app/questions/queries/getQuestion.ts b/app/questions/queries/getQuestion.ts new file mode 100644 index 0000000..410d802 --- /dev/null +++ b/app/questions/queries/getQuestion.ts @@ -0,0 +1,16 @@ +import { NotFoundError, SessionContext } from "blitz" +import db, { FindOneQuestionArgs } from "db" + +type GetQuestionInput = { + where: FindOneQuestionArgs["where"] + // Only available if a model relationship exists + // include?: FindOneQuestionArgs['include'] +} + +export default async function getQuestion( + { where /* include */ }: GetQuestionInput, + ctx: Record = {} +) { + const question = await db.question.findOne({ where, include: { choices: true } }) + return question +} diff --git a/app/questions/queries/getQuestions.ts b/app/questions/queries/getQuestions.ts new file mode 100644 index 0000000..81db034 --- /dev/null +++ b/app/questions/queries/getQuestions.ts @@ -0,0 +1,35 @@ +import { SessionContext } from "blitz" +import db, { FindManyQuestionArgs } from "db" + +type GetQuestionsInput = { + where?: FindManyQuestionArgs["where"] + orderBy?: FindManyQuestionArgs["orderBy"] + skip?: FindManyQuestionArgs["skip"] + take?: FindManyQuestionArgs["take"] + // Only available if a model relationship exists + // include?: FindManyQuestionArgs['include'] +} + +export default async function getQuestions( + { where, orderBy, cursor, take, skip }: GetQuestionsInput, + ctx: Record = {} +) { + const questions = await db.question.findMany({ + where, + orderBy, + cursor, + take, + skip, + include: { choices: true }, + }) + + const count = await db.question.count() + const hasMore = typeof take === "number" ? skip + take < count : false + const nextPage = hasMore ? { take, skip: skip + take! } : null + + return { + questions, + nextPage, + hasMore, + } +} diff --git a/blitzjs.com b/blitzjs.com new file mode 160000 index 0000000..2edbfef --- /dev/null +++ b/blitzjs.com @@ -0,0 +1 @@ +Subproject commit 2edbfef3ab110da47c67bc662ac0515f53a9c344 diff --git a/db/migrations/20200912171755-initial-migration/README.md b/db/migrations/20200912171755-initial-migration/README.md new file mode 100644 index 0000000..cf72f94 --- /dev/null +++ b/db/migrations/20200912171755-initial-migration/README.md @@ -0,0 +1,87 @@ +# Migration `20200912171755-initial-migration` + +This migration has been generated at 9/12/2020, 7:17:55 PM. +You can check out the [state of the schema](./schema.prisma) after the migration. + +## Database Steps + +```sql +CREATE TABLE "User" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "name" TEXT, + "email" TEXT NOT NULL, + "hashedPassword" TEXT, + "role" TEXT NOT NULL DEFAULT 'user' +) + +CREATE TABLE "Session" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "expiresAt" DATETIME, + "handle" TEXT NOT NULL, + "userId" INTEGER, + "hashedSessionToken" TEXT, + "antiCSRFToken" TEXT, + "publicData" TEXT, + "privateData" TEXT, + + FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE +) + +CREATE UNIQUE INDEX "User.email_unique" ON "User"("email") + +CREATE UNIQUE INDEX "Session.handle_unique" ON "Session"("handle") +``` + +## Changes + +```diff +diff --git schema.prisma schema.prisma +migration ..20200912171755-initial-migration +--- datamodel.dml ++++ datamodel.dml +@@ -1,0 +1,38 @@ ++// This is your Prisma schema file, ++// learn more about it in the docs: https://pris.ly/d/prisma-schema ++ ++datasource db { ++ provider = ["sqlite", "postgres"] ++ url = "***" ++} ++ ++generator client { ++ provider = "prisma-client-js" ++} ++ ++// -------------------------------------- ++ ++model User { ++ id Int @default(autoincrement()) @id ++ createdAt DateTime @default(now()) ++ updatedAt DateTime @updatedAt ++ name String? ++ email String @unique ++ hashedPassword String? ++ role String @default("user") ++ sessions Session[] ++} ++ ++model Session { ++ id Int @default(autoincrement()) @id ++ createdAt DateTime @default(now()) ++ updatedAt DateTime @updatedAt ++ expiresAt DateTime? ++ handle String @unique ++ user User? @relation(fields: [userId], references: [id]) ++ userId Int? ++ hashedSessionToken String? ++ antiCSRFToken String? ++ publicData String? ++ privateData String? ++} +``` + + diff --git a/db/migrations/20200912171755-initial-migration/schema.prisma b/db/migrations/20200912171755-initial-migration/schema.prisma new file mode 100644 index 0000000..7308a38 --- /dev/null +++ b/db/migrations/20200912171755-initial-migration/schema.prisma @@ -0,0 +1,38 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +datasource db { + provider = ["sqlite", "postgres"] + url = "***" +} + +generator client { + provider = "prisma-client-js" +} + +// -------------------------------------- + +model User { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + name String? + email String @unique + hashedPassword String? + role String @default("user") + sessions Session[] +} + +model Session { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + expiresAt DateTime? + handle String @unique + user User? @relation(fields: [userId], references: [id]) + userId Int? + hashedSessionToken String? + antiCSRFToken String? + publicData String? + privateData String? +} diff --git a/db/migrations/20200912171755-initial-migration/steps.json b/db/migrations/20200912171755-initial-migration/steps.json new file mode 100644 index 0000000..c8aeb53 --- /dev/null +++ b/db/migrations/20200912171755-initial-migration/steps.json @@ -0,0 +1,398 @@ +{ + "version": "0.3.14-fixed", + "steps": [ + { + "tag": "CreateSource", + "source": "db" + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Source", + "source": "db" + }, + "argument": "provider", + "value": "[\"sqlite\", \"postgres\"]" + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Source", + "source": "db" + }, + "argument": "url", + "value": "\"***\"" + }, + { + "tag": "CreateModel", + "model": "User" + }, + { + "tag": "CreateField", + "model": "User", + "field": "id", + "type": "Int", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "User", + "field": "id" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "User", + "field": "id" + }, + "directive": "default" + }, + "argument": "", + "value": "autoincrement()" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "User", + "field": "id" + }, + "directive": "id" + } + }, + { + "tag": "CreateField", + "model": "User", + "field": "createdAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "User", + "field": "createdAt" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "User", + "field": "createdAt" + }, + "directive": "default" + }, + "argument": "", + "value": "now()" + }, + { + "tag": "CreateField", + "model": "User", + "field": "updatedAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "User", + "field": "updatedAt" + }, + "directive": "updatedAt" + } + }, + { + "tag": "CreateField", + "model": "User", + "field": "name", + "type": "String", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "User", + "field": "email", + "type": "String", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "User", + "field": "email" + }, + "directive": "unique" + } + }, + { + "tag": "CreateField", + "model": "User", + "field": "hashedPassword", + "type": "String", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "User", + "field": "role", + "type": "String", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "User", + "field": "role" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "User", + "field": "role" + }, + "directive": "default" + }, + "argument": "", + "value": "\"user\"" + }, + { + "tag": "CreateField", + "model": "User", + "field": "sessions", + "type": "Session", + "arity": "List" + }, + { + "tag": "CreateModel", + "model": "Session" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "id", + "type": "Int", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Session", + "field": "id" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Session", + "field": "id" + }, + "directive": "default" + }, + "argument": "", + "value": "autoincrement()" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Session", + "field": "id" + }, + "directive": "id" + } + }, + { + "tag": "CreateField", + "model": "Session", + "field": "createdAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Session", + "field": "createdAt" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Session", + "field": "createdAt" + }, + "directive": "default" + }, + "argument": "", + "value": "now()" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "updatedAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Session", + "field": "updatedAt" + }, + "directive": "updatedAt" + } + }, + { + "tag": "CreateField", + "model": "Session", + "field": "expiresAt", + "type": "DateTime", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "handle", + "type": "String", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Session", + "field": "handle" + }, + "directive": "unique" + } + }, + { + "tag": "CreateField", + "model": "Session", + "field": "user", + "type": "User", + "arity": "Optional" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Session", + "field": "user" + }, + "directive": "relation" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Session", + "field": "user" + }, + "directive": "relation" + }, + "argument": "fields", + "value": "[userId]" + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Session", + "field": "user" + }, + "directive": "relation" + }, + "argument": "references", + "value": "[id]" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "userId", + "type": "Int", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "hashedSessionToken", + "type": "String", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "antiCSRFToken", + "type": "String", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "publicData", + "type": "String", + "arity": "Optional" + }, + { + "tag": "CreateField", + "model": "Session", + "field": "privateData", + "type": "String", + "arity": "Optional" + } + ] +} \ No newline at end of file diff --git a/db/migrations/20200912172104-init-db/README.md b/db/migrations/20200912172104-init-db/README.md new file mode 100644 index 0000000..5acdc1b --- /dev/null +++ b/db/migrations/20200912172104-init-db/README.md @@ -0,0 +1,69 @@ +# Migration `20200912172104-init-db` + +This migration has been generated at 9/12/2020, 7:21:04 PM. +You can check out the [state of the schema](./schema.prisma) after the migration. + +## Database Steps + +```sql +CREATE TABLE "Question" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "text" TEXT NOT NULL +) + +CREATE TABLE "Choice" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "text" TEXT NOT NULL, + "votes" INTEGER NOT NULL DEFAULT 0, + "questionId" INTEGER NOT NULL, + + FOREIGN KEY ("questionId") REFERENCES "Question"("id") ON DELETE CASCADE ON UPDATE CASCADE +) +``` + +## Changes + +```diff +diff --git schema.prisma schema.prisma +migration 20200912171755-initial-migration..20200912172104-init-db +--- datamodel.dml ++++ datamodel.dml +@@ -2,9 +2,9 @@ + // learn more about it in the docs: https://pris.ly/d/prisma-schema + datasource db { + provider = ["sqlite", "postgres"] +- url = "***" ++ url = "***" + } + generator client { + provider = "prisma-client-js" +@@ -35,4 +35,22 @@ + antiCSRFToken String? + publicData String? + privateData String? + } ++ ++model Question { ++ id Int @default(autoincrement()) @id ++ createdAt DateTime @default(now()) ++ updatedAt DateTime @updatedAt ++ text String ++ choices Choice[] ++} ++ ++model Choice { ++ id Int @default(autoincrement()) @id ++ createdAt DateTime @default(now()) ++ updatedAt DateTime @updatedAt ++ text String ++ votes Int @default(0) ++ question Question @relation(fields: [questionId], references: [id]) ++ questionId Int ++} +``` + + diff --git a/db/migrations/20200912172104-init-db/schema.prisma b/db/migrations/20200912172104-init-db/schema.prisma new file mode 100644 index 0000000..d317934 --- /dev/null +++ b/db/migrations/20200912172104-init-db/schema.prisma @@ -0,0 +1,56 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +datasource db { + provider = ["sqlite", "postgres"] + url = "***" +} + +generator client { + provider = "prisma-client-js" +} + +// -------------------------------------- + +model User { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + name String? + email String @unique + hashedPassword String? + role String @default("user") + sessions Session[] +} + +model Session { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + expiresAt DateTime? + handle String @unique + user User? @relation(fields: [userId], references: [id]) + userId Int? + hashedSessionToken String? + antiCSRFToken String? + publicData String? + privateData String? +} + +model Question { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + text String + choices Choice[] +} + +model Choice { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + text String + votes Int @default(0) + question Question @relation(fields: [questionId], references: [id]) + questionId Int +} diff --git a/db/migrations/20200912172104-init-db/steps.json b/db/migrations/20200912172104-init-db/steps.json new file mode 100644 index 0000000..2e5955d --- /dev/null +++ b/db/migrations/20200912172104-init-db/steps.json @@ -0,0 +1,305 @@ +{ + "version": "0.3.14-fixed", + "steps": [ + { + "tag": "CreateModel", + "model": "Question" + }, + { + "tag": "CreateField", + "model": "Question", + "field": "id", + "type": "Int", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Question", + "field": "id" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Question", + "field": "id" + }, + "directive": "default" + }, + "argument": "", + "value": "autoincrement()" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Question", + "field": "id" + }, + "directive": "id" + } + }, + { + "tag": "CreateField", + "model": "Question", + "field": "createdAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Question", + "field": "createdAt" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Question", + "field": "createdAt" + }, + "directive": "default" + }, + "argument": "", + "value": "now()" + }, + { + "tag": "CreateField", + "model": "Question", + "field": "updatedAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Question", + "field": "updatedAt" + }, + "directive": "updatedAt" + } + }, + { + "tag": "CreateField", + "model": "Question", + "field": "text", + "type": "String", + "arity": "Required" + }, + { + "tag": "CreateField", + "model": "Question", + "field": "choices", + "type": "Choice", + "arity": "List" + }, + { + "tag": "CreateModel", + "model": "Choice" + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "id", + "type": "Int", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Choice", + "field": "id" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Choice", + "field": "id" + }, + "directive": "default" + }, + "argument": "", + "value": "autoincrement()" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Choice", + "field": "id" + }, + "directive": "id" + } + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "createdAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Choice", + "field": "createdAt" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Choice", + "field": "createdAt" + }, + "directive": "default" + }, + "argument": "", + "value": "now()" + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "updatedAt", + "type": "DateTime", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Choice", + "field": "updatedAt" + }, + "directive": "updatedAt" + } + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "text", + "type": "String", + "arity": "Required" + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "votes", + "type": "Int", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Choice", + "field": "votes" + }, + "directive": "default" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Choice", + "field": "votes" + }, + "directive": "default" + }, + "argument": "", + "value": "0" + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "question", + "type": "Question", + "arity": "Required" + }, + { + "tag": "CreateDirective", + "location": { + "path": { + "tag": "Field", + "model": "Choice", + "field": "question" + }, + "directive": "relation" + } + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Choice", + "field": "question" + }, + "directive": "relation" + }, + "argument": "fields", + "value": "[questionId]" + }, + { + "tag": "CreateArgument", + "location": { + "tag": "Directive", + "path": { + "tag": "Field", + "model": "Choice", + "field": "question" + }, + "directive": "relation" + }, + "argument": "references", + "value": "[id]" + }, + { + "tag": "CreateField", + "model": "Choice", + "field": "questionId", + "type": "Int", + "arity": "Required" + } + ] +} \ No newline at end of file diff --git a/db/migrations/migrate.lock b/db/migrations/migrate.lock new file mode 100644 index 0000000..0391f0b --- /dev/null +++ b/db/migrations/migrate.lock @@ -0,0 +1,4 @@ +# Prisma Migrate lockfile v1 + +20200912171755-initial-migration +20200912172104-init-db \ No newline at end of file diff --git a/db/schema.prisma b/db/schema.prisma index 9adb150..f6fc26e 100644 --- a/db/schema.prisma +++ b/db/schema.prisma @@ -36,3 +36,21 @@ model Session { publicData String? privateData String? } + +model Question { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + text String + choices Choice[] +} + +model Choice { + id Int @default(autoincrement()) @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + text String + votes Int @default(0) + question Question @relation(fields: [questionId], references: [id]) + questionId Int +} diff --git a/package-lock.json b/package-lock.json index 7f8a4b1..29e3c1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1650,6 +1650,11 @@ "minimist": "^1.2.0" } }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, "@eslint/eslintrc": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", @@ -2180,6 +2185,88 @@ } } }, + "@material-ui/core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz", + "integrity": "sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.10.0", + "@material-ui/system": "^4.9.14", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.10.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/styles": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz", + "integrity": "sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.13.tgz", + "integrity": "sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A==" + } + } + }, + "@material-ui/system": { + "version": "4.9.14", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", + "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.13.tgz", + "integrity": "sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" + }, + "@material-ui/utils": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz", + "integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -3271,14 +3358,12 @@ "@types/prop-types": { "version": "15.7.3", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" }, "@types/react": { "version": "16.9.49", "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.49.tgz", "integrity": "sha512-DtLFjSj0OYAdVLBbyjhuV9CdGVHCkHn2R+xr3XkBvK2rS1Y1tkc14XSGjYgm5Fjjr90AxH9tiSzc1pCFMGO06g==", - "dev": true, "requires": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -3293,6 +3378,14 @@ "@types/react": "*" } }, + "@types/react-transition-group": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", + "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", + "requires": { + "@types/react": "*" + } + }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -5252,6 +5345,11 @@ } } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -5720,6 +5818,15 @@ } } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", @@ -5784,8 +5891,7 @@ "csstype": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz", - "integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==", - "dev": true + "integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==" }, "cyclist": { "version": "1.0.1", @@ -6095,6 +6201,15 @@ "integrity": "sha512-k7hRNKAiPJXD2aBqfahSo4/01cTsKWXf+LqJgglnkN2Nz8TsxXKQBXHhKe0Ye9fEfHEZY49uSA5Sr3AqP/sWKA==", "dev": true }, + "dom-helpers": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "dom-serializer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.0.1.tgz", @@ -7973,6 +8088,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", @@ -8081,6 +8204,11 @@ "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==" }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -8437,6 +8565,11 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, "is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -10776,6 +10909,84 @@ "verror": "1.10.0" } }, + "jss": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.4.0.tgz", + "integrity": "sha512-l7EwdwhsDishXzqTc3lbsbyZ83tlUl5L/Hb16pHCvZliA9lRDdNBZmHzeJHP0sxqD0t1mrMmMR8XroR12JBYzw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.4.0.tgz", + "integrity": "sha512-9oDjsQ/AgdBbMyRjc06Kl3P8lDCSEts2vYZiPZfGAxbGCegqE4RnMob3mDaBby5H9vL9gWmyyImhLRWqIkRUCw==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.4.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.4.0.tgz", + "integrity": "sha512-BYJ+Y3RUYiMEgmlcYMLqwbA49DcSWsGgHpVmEEllTC8MK5iJ7++pT9TnKkKBnNZZxTV75ycyFCR5xeLSOzVm4A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0" + } + }, + "jss-plugin-global": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.4.0.tgz", + "integrity": "sha512-b8IHMJUmv29cidt3nI4bUI1+Mo5RZE37kqthaFpmxf5K7r2aAegGliAw4hXvA70ca6ckAoXMUl4SN/zxiRcRag==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0" + } + }, + "jss-plugin-nested": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.4.0.tgz", + "integrity": "sha512-cKgpeHIxAP0ygeWh+drpLbrxFiak6zzJ2toVRi/NmHbpkNaLjTLgePmOz5+67ln3qzJiPdXXJB1tbOyYKAP4Pw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.4.0.tgz", + "integrity": "sha512-j/t0R40/2fp+Nzt6GgHeUFnHVY2kPGF5drUVlgkcwYoHCgtBDOhTTsOfdaQFW6sHWfoQYgnGV4CXdjlPiRrzwA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.4.0.tgz", + "integrity": "sha512-w8504Cdfu66+0SJoLkr6GUQlEb8keHg8ymtJXdVHWh0YvFxDG2l/nS93SI5Gfx0fV29dO6yUugXnKzDFJxrdFQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.4.0.tgz", + "integrity": "sha512-DpF+/a+GU8hMh/948sBGnKSNfKkoHg2p9aRFUmyoyxgKjOeH9n74Ht3Yt8lOgdZsuWNJbPrvaa3U4PXKwxVpTQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.4.0" + } + }, "jsx-ast-utils": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", @@ -13396,6 +13607,11 @@ "ts-pnp": "^1.1.6" } }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -13866,6 +14082,17 @@ } } }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -16014,6 +16241,11 @@ "setimmediate": "^1.0.4" } }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", diff --git a/package.json b/package.json index 2deb000..909309a 100644 --- a/package.json +++ b/package.json @@ -28,16 +28,17 @@ ] }, "dependencies": { + "@material-ui/core": "4.11.0", "@prisma/cli": "2.6.2", "@prisma/client": "2.6.2", "blitz": "0.22.0", + "final-form": "4.20.1", "react": "0.0.0-experimental-7f28234f8", "react-dom": "0.0.0-experimental-7f28234f8", "react-error-boundary": "2.3.2", + "react-final-form": "6.5.1", "secure-password": "4.0.0", - "zod": "1.11.5", - "final-form": "4.20.1", - "react-final-form": "6.5.1" + "zod": "1.11.5" }, "devDependencies": { "@testing-library/jest-dom": "5.11.4",