Skip to content

Commit

Permalink
Merge pull request #49 from RickCarlino/prod
Browse files Browse the repository at this point in the history
Multiple Updates
  • Loading branch information
RickCarlino authored Nov 14, 2023
2 parents 7afda8e + a38dc54 commit 071d552
Show file tree
Hide file tree
Showing 20 changed files with 1,055 additions and 644 deletions.
1,306 changes: 728 additions & 578 deletions package-lock.json

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,46 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@types/jest": "^29.5.5",
"@types/node": "^20.8.2",
"@types/react": "^18.2.24",
"@types/react-dom": "^18.2.8",
"@types/jest": "^29.5.8",
"@types/node": "^20.9.0",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"jest": "^29.7.0",
"prisma": "^5.3.1",
"prisma": "^5.5.2",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"dependencies": {
"@google-cloud/language": "^6.1.0",
"@google-cloud/language": "^6.1.1",
"@google-cloud/text-to-speech": "^5.0.1",
"@google-cloud/translate": "^8.0.2",
"@mantine/core": "^7.1.2",
"@mantine/ds": "^7.1.2",
"@mantine/form": "^7.1.2",
"@mantine/ds": "^7.2.1",
"@mantine/form": "^7.2.1",
"@mantine/hooks": "^7.1.2",
"@mantine/next": "^6.0.19",
"@mantine/notifications": "^7.1.2",
"@mantine/next": "^6.0.21",
"@mantine/notifications": "^7.2.1",
"@next-auth/prisma-adapter": "^1.0.7",
"@prisma/client": "^5.3.1",
"@tabler/icons-react": "^2.38.0",
"@tanstack/react-query": "^4.35.7",
"@prisma/client": "^5.5.2",
"@tabler/icons-react": "^2.40.0",
"@tanstack/react-query": "^4.36.1",
"@trpc/client": "^10.38.5",
"@trpc/next": "^10.38.5",
"@trpc/next": "^10.43.3",
"@trpc/react-query": "^10.38.5",
"@trpc/server": "^10.38.5",
"dotenv": "^16.3.1",
"eslint": "^8.50.0",
"eslint-config-next": "^13.5.4",
"next": "^13.5.4",
"next-auth": "^4.23.2",
"nodemailer": "^6.9.5",
"openai": "^4.11.1",
"prom-client": "^14.2.0",
"eslint": "^8.53.0",
"eslint-config-next": "^14.0.2",
"next": "^14.0.2",
"next-auth": "^4.24.5",
"nodemailer": "^6.9.7",
"openai": "^4.17.4",
"prom-client": "^15.0.0",
"radash": "^11.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"zod": "^3.22.3"
"zod": "^3.22.4"
},
"jest": {
"transform": {
Expand Down
1 change: 1 addition & 0 deletions pages/_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const NavBar = () => {
{ path: "/study", name: "Study" },
{ path: "/create", name: "Create" },
{ path: "/cards", name: "Edit" },
{ path: "/history", name: "History" },
{ path: "/user", name: "Settings" },
];

Expand Down
13 changes: 10 additions & 3 deletions pages/cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface FileImportButtonProps {
// It's a file picker that has an "onReady" callback.
// When the user selects a file, it calls the callback with the file contents:
const FileImportButton = ({ onReady }: FileImportButtonProps) => {
const onChange = (file: File) => {
const onChange = (file: File | null) => {
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
Expand Down Expand Up @@ -56,7 +56,7 @@ const Edit: React.FC = () => {
const deleteFlagged = trpc.deleteFlaggedCards.useMutation();
const exportCards = trpc.exportCards.useMutation();
const importCards = trpc.importCards.useMutation();

const flagObnoxious = trpc.flagObnoxious.useMutation();
const doDeleteFlagged = () => {
const warning = "Are you sure you want to delete all flagged cards?";
if (!confirm(warning)) return;
Expand All @@ -78,15 +78,22 @@ const Edit: React.FC = () => {
if (cards.data) {
content = <CardTable cards={cards.data} />;
}
const doFlagObnoxious = () => {
const warning =
"Flag ALL cards with ease below 1.3 *OR* more than 7 lapses?";
if (!confirm(warning)) return;
flagObnoxious.mutateAsync({}).then(() => location.reload());
};
return Authed(
<Container size="s">
<h1>Manage Cards</h1>
<Button onClick={doDeleteFlagged}>Delete Flagged Cards</Button>
<Button onClick={doFlagObnoxious}>Flag Obnoxious Cards</Button>
<Button onClick={doExport}>Export Cards</Button>
<FileImportButton
onReady={(data) => {
const desired = data.length;
alert("This is going to take a while. Please wait...");
alert("This is going to take a while. Are you ready?");
importCards.mutateAsync(data).then(({ count }) => {
alert(`Imported ${count}/${desired} cards.`);
location.reload();
Expand Down
1 change: 0 additions & 1 deletion pages/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ const CreateCardPage: React.FC<CreateCardProps> = ({}) => {
setIsLoading(false);
setText("");
});

};
const start = (
<Paper>
Expand Down
84 changes: 84 additions & 0 deletions pages/history.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { prismaClient } from "@/server/prisma-client";
import { cleanString } from "@/utils/clean-string";
import { GetServerSidePropsContext } from "next";
import { getSession } from "next-auth/react";
import React from "react";

export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ req: context.req });
const userID =
"" +
(
await prismaClient.user.findUnique({
where: { email: session?.user?.email || "" },
})
)?.id || "";
const transcripts = (
await prismaClient.transcript.findMany({
where: { card: { userId: userID } },
orderBy: {
recordedAt: "desc",
},
include: {
card: true,
},
})
)
.filter((t) => {
return cleanString(t.value) !== cleanString(t.card.term);
})
.map((t) => {
return {
id: t.id,
grade: t.grade.toPrecision(1),
value: t.value,
term: t.card.term,
};
});
// Pass the transcripts to the page via props
return { props: { transcripts } };
}

type Transcript = {
id: number;
grade: string;
value: string;
term: string;
};

type Props = {
transcripts: Transcript[];
};

const TranscriptsPage = ({ transcripts }: Props) => {
return (
<div>
<h1>Transcripts</h1>
<p>
<strong>NOTE:</strong> Only cards that are not an exact match are
displayed here.
</p>
<hr />
<table>
<thead>
<tr>
<th>Grade</th>
<th>Phrase</th>
<th>What You Said</th>
</tr>
</thead>
<tbody>
{transcripts.map((transcript) => (
<tr key={transcript.id}>
<td>{transcript.grade}</td>
<td>{transcript.term}</td>
<td>{transcript.value}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};

export default TranscriptsPage;
10 changes: 8 additions & 2 deletions pages/study.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from "../utils/_study_reducer";
import { QuizFailure, linkToEditPage } from "../components/quiz-failure";
import { beep } from "@/utils/beep";
import Link from "next/link";

type Props = {
quizzes: Quiz[];
Expand Down Expand Up @@ -86,11 +87,13 @@ function Study(props: Props) {
["x", () => quiz && doFail(quiz.id)],
["z", () => quiz && doFlag(quiz.id)],
]);
const deps = [quiz?.id, quiz?.lessonType, !!state.failure];
const linterRequiresThis = deps.join(".");
useEffect(() => {
if (quiz && !state.failure) {
playAudio(quiz.quizAudio);
}
}, [`${quiz?.id},${quiz?.lessonType},${!!state.failure}`]);
}, [linterRequiresThis]);

const doFail = (id: number) => {
dispatch({ type: "USER_GAVE_UP", id });
Expand Down Expand Up @@ -131,7 +134,10 @@ function Study(props: Props) {
return (
<div>
<h1>No Cards Due</h1>
<p>Consider adding more by clicking "import"</p>
<p>
You must <Link href="/create">create new cards</Link> or{" "}
<Link href="/cards">import cards from a backup file</Link>.
</p>
</div>
);
}
Expand Down
67 changes: 60 additions & 7 deletions pages/user.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,68 @@
import { prismaClient } from "@/server/prisma-client";
import { Container } from "@mantine/core";
import { GetServerSidePropsContext } from "next";
import { getSession } from "next-auth/react";
import Authed from "../components/authed";
import { UserSettings } from "@prisma/client";

export default function User() {
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ req: context.req });
const userId =
"" +
(
await prismaClient.user.findUnique({
where: { email: session?.user?.email || "" },
})
)?.id;
if (!userId) {
throw new Error("User not found");
}

const userSettings = await prismaClient.userSettings.upsert({
where: { userId: userId },
update: {},
create: { userId },
});
// Pass the transcripts to the page via props
return { props: { userSettings: JSON.parse(JSON.stringify(userSettings)) } };
}

type SettingsDisplayProps<T extends keyof UserSettings> = {
setting: T;
description: string;
value: UserSettings[T];
};

function SettingsDisplay<T extends keyof UserSettings>(
props: SettingsDisplayProps<T>,
) {
return (
<li>
<label>
{props.description}
<input type="text" defaultValue={"" + props.value} />
</label>
</li>
);
}

type Props = {
userSettings: UserSettings;
};

export default function User(props: Props) {
return Authed(
<Container size="s">
<h1>User Settings</h1>
<p>
Eventually, I want this page to allow things like changing email
address, changing password, and deleting account. It also needs stats on
how much you have studied.
</p>
<h1>THIS DOESN'T WORK YET</h1>
<ul>
<SettingsDisplay
setting={"playbackPercentage"}
description={
"What percentage of recordings will be played back to you for review?"
}
value={props.userSettings.playbackPercentage}
/>
</ul>
</Container>,
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- CreateTable
CREATE TABLE "Transcript" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"cardId" INTEGER NOT NULL,
"transcript" TEXT NOT NULL,
"recordedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"grade" REAL NOT NULL DEFAULT 0,
CONSTRAINT "Transcript_cardId_fkey" FOREIGN KEY ("cardId") REFERENCES "Card" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);

-- CreateIndex
CREATE UNIQUE INDEX "Transcript_cardId_key" ON "Transcript"("cardId");
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Warnings:
- You are about to drop the column `transcript` on the `Transcript` table. All the data in the column will be lost.
- Added the required column `value` to the `Transcript` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Transcript" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"cardId" INTEGER NOT NULL,
"value" TEXT NOT NULL,
"recordedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"grade" REAL NOT NULL DEFAULT 0,
CONSTRAINT "Transcript_cardId_fkey" FOREIGN KEY ("cardId") REFERENCES "Card" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_Transcript" ("cardId", "grade", "id", "recordedAt") SELECT "cardId", "grade", "id", "recordedAt" FROM "Transcript";
DROP TABLE "Transcript";
ALTER TABLE "new_Transcript" RENAME TO "Transcript";
CREATE UNIQUE INDEX "Transcript_cardId_key" ON "Transcript"("cardId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- CreateTable
CREATE TABLE "UserSettings" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"userId" TEXT NOT NULL,
"playbackPercentage" REAL NOT NULL DEFAULT 1,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "UserSettings_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);

-- CreateIndex
CREATE UNIQUE INDEX "UserSettings_userId_key" ON "UserSettings"("userId");
Loading

0 comments on commit 071d552

Please sign in to comment.