Skip to content

Commit

Permalink
feat: migrations and feedback UI
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinmarnold committed Dec 7, 2023
1 parent 4443b39 commit 2cf56f7
Show file tree
Hide file tree
Showing 7 changed files with 396 additions and 181 deletions.
53 changes: 47 additions & 6 deletions packages/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,55 @@ yarn dev
pnpm dev
```

### Supabase migrations
## Migration instructions

The first time you setup a new Supabase project, migrations must be applied.
To make changes to the schema moving forward, you can update the DB directly from Supabase DB. When ready, run `supabase db remote commit`. You will need to have Docker running locally for this to succeed. When complete, there will be a new file in `supabase/migrations` with a name like `20230821153353_remote_commit.sql`. Commit this file to source control and it will automatically be applied to the DB when merged.

```
supabase login
supabase link --project-ref $PROJECT_ID
### New project

```bash
# from nextjs project
cd packages/web

# connect to project
supabase link --project-ref weqbsjuunfkxuyhsutzx

# sync project with existing migrations
supabase db push

# pull remote project changes to local code
supabase db remote commit
```

To make changes to the schema moving forward, you can update the DB directly from Supabase DB. When ready, run `supabase db remote commit`. You will need to have Docker running locally for this to succeed. When complete, there will be a new file in `supabase/migrations` with a name like `20230821153353_remote_commit.sql`. Commit this file to source control and it will automatically be applied to the DB when merged.
This will create a new file in `packages/web/supabase/migrations`. For some reason, Supabase adds a bunch of junk that you can remove from the generated migration.

```sql
-- delete all this
alter table "auth"."saml_relay_states" add column "flow_state_id" uuid;

alter table "auth"."sessions" add column "ip" inet;

alter table "auth"."sessions" add column "refreshed_at" timestamp without time zone;

alter table "auth"."sessions" add column "user_agent" text;

CREATE INDEX flow_state_created_at_idx ON auth.flow_state USING btree (created_at DESC);

CREATE INDEX mfa_challenge_created_at_idx ON auth.mfa_challenges USING btree (created_at DESC);

CREATE INDEX mfa_factors_user_id_idx ON auth.mfa_factors USING btree (user_id);

CREATE INDEX refresh_tokens_updated_at_idx ON auth.refresh_tokens USING btree (updated_at DESC);

CREATE INDEX saml_relay_states_created_at_idx ON auth.saml_relay_states USING btree (created_at DESC);

CREATE INDEX sessions_not_after_idx ON auth.sessions USING btree (not_after DESC);

alter table "auth"."saml_relay_states" add constraint "saml_relay_states_flow_state_id_fkey" FOREIGN KEY (flow_state_id) REFERENCES auth.flow_state(id) ON DELETE CASCADE not valid;

alter table "auth"."saml_relay_states" validate constraint "saml_relay_states_flow_state_id_fkey";
```

## Importing large data

Increase session timeout: `alter role authenticator set statement_timeout = '120s';`
Original file line number Diff line number Diff line change
@@ -1,87 +1,87 @@

"use client";

// Import necessary modules and components
import { supabase } from '../../lib/supabase/supabaseClient';
import ThreeCardLayout from '../../components/ThreeCardLayout';
import ThreeCardLayout from "../../components/ThreeCardLayout";
import { supabase } from "../../lib/supabase/supabaseClient";
// import NextButton from '@/components/NextButton';
import { useState, useEffect } from "react";
import { ICard } from '@/lib/api';
import { ICard } from "@/lib/api";
import { TABLES } from "@/lib/supabase/db";
import { useEffect, useState } from "react";

export const dynamic = "force-dynamic";

export default function UserFeedback() {
// const [currentIndex, setCurrentIndex] = useState<number>(randint(0,177));
const [userName, setUserName] = useState("");
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [answered, setAnswered] = useState<Set<number>>(new Set());
const [fullData, setFullData] = useState<Array<Array<ICard>> | null>(null);

const [cardArray, setCardArray] = useState<Array<Array<ICard>> | null>(null);


// Not the best way to do it-- we really should make each of these a new page and the next/prev buttons
// should be linked to the next/prev page. But this is a quick fix for now.
const question_idArray = Array.from({ length: 98 }, (_, index) => index);


const handlePrevClick = () => {
if (fullData) {
setCardArray(fullData);
//wraps around
setCurrentIndex((currentIndex - 1 + question_idArray.length) % question_idArray.length);
} else {
alert("Please wait for the rest of the cards to finish loading...");
}
};
// const handlePrevClick = () => {
// if (fullData) {
// setCardArray(fullData);
// //wraps around
// setCurrentIndex(
// (currentIndex - 1 + question_idArray.length) % question_idArray.length
// );
// } else {
// alert("Please wait for the rest of the cards to finish loading...");
// }
// };

const handleNextClick = () => {
if (fullData) {
setCardArray(fullData);
//wraps around
setCurrentIndex((currentIndex + 1) % question_idArray.length);
setAnswered(new Set());
} else {
alert("Please wait for the rest of the cards to finish loading...");
}

};

//const handleNameChange = (e) => {
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUserName(e.target.value);
}
};

useEffect(() => {
const getCard = async () => {
try {
const cardsArray: Array<Array<ICard>> = [];
const { data: cards, error } = await supabase
.from('sawt_cards')
.select('*')
.from(TABLES.FEEDBACK_CARDS)
.select("*")
.eq("question_id", 0);
if (cards) {
cardsArray.push(cards);
}
setCardArray(cardsArray);
console.log(cards);
}catch (error) {
} catch (error) {
console.error("Error fetching cards: ", error);
// Handle the error appropriately in your UI
}
getCards();
}
getCard();
};
getCard();
}, []); // Run this effect only once when the component mounts


const getCards = async () => {
const cardsArray: Array<Array<ICard>> = [];
try {
for (let i = 1; i <= question_idArray.length; i++) {
const { data: cards, error } = await supabase
.from('sawt_cards')
.select('*')
.from(TABLES.FEEDBACK_CARDS)
.select("*")
.eq("question_id", i);

if (error) {
console.error("Error fetching cards: ", error);
// Handle the error appropriately in your UI
Expand All @@ -91,49 +91,54 @@ export default function UserFeedback() {
if (cards) {
cardsArray.push(cards);
}
}
}
setFullData(cardsArray);
console.log(fullData);
// console.log(fullData);
//setCurrentIndex(Math.floor(Math.random() * cardsArray.length));


} catch (error) {
console.error("Error fetching cards: ", error);
// Handle the error appropriately in your UI
}
};


if (!cardArray) {
return <div>Loading...</div>;
}

return (
<>
<div className="rounded-lg bg-blue p-6 text-primary">
<label className="block text-gray-700 text-lg font-bold mb-2">
Please Enter Your Name:
</label>
<div className="flex">
<input
className="appearance-none rounded w-80 py-2 px-3 leading-tight text-lg focus:outline-none focus:border-blue-500"
type="text"
value={userName}
onChange={handleNameChange}
placeholder="Your Name Here"
/>
<div className="h-full bg-blue px-6 text-primary md:flex">
<div className="md:grow"></div>
<div className="pb-24 md:w-3/4 md:max-w-2xl">
<div className="rounded-lg bg-blue p-6 text-primary">
<label className="mb-2 block text-lg font-bold text-gray-700">
Please Enter Your Name:
</label>
<div className="flex">
<input
className="focus:border-blue-500 w-80 appearance-none rounded px-3 py-2 text-lg leading-tight focus:outline-none"
type="text"
value={userName}
onChange={handleNameChange}
placeholder="Your Name Here"
/>
</div>
</div>
<ThreeCardLayout
cards={cardArray[currentIndex]}
userName={userName}
answered={answered}
setAnswered={setAnswered}
/>
{answered.size === 3 && (
<button
onClick={handleNextClick}
className="bg-blue-500 w-full rounded bg-secondary px-4 py-2 text-lg text-white"
>
Next question
</button>
)}
</div>
<ThreeCardLayout cards={cardArray[currentIndex]} userName={userName} />
<div>
<div className="float-left">
<button onClick={handlePrevClick} className= "bg-blue-500 rounded bg-secondary px-4 py-2 text-white">Previous</button>
</div>

<div className="float-right">
<button onClick={handleNextClick} className= "bg-blue-500 rounded bg-secondary px-4 py-2 text-white">Next</button>
</div>
</div>
</>
<div className="md:grow"></div>
</div>
);
}
81 changes: 45 additions & 36 deletions packages/web/components/CommentBoxes.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,63 @@

import { ICard } from "@/lib/api";
import { faComment } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useState } from "react";

interface CommentBoxProps {
scores: Record<string, number>
scores: Record<string, number>;
card: ICard;
onSubmit: (data: {
comment: string;
card: ICard;
onSubmit: (data: { comment: string, card: ICard, scores: Record<string, number> }) => void;
onReset: () => void;
scores: Record<string, number>;
index: number;
}) => void;
onReset: () => void;
index: number;
}

export default function CommentBox({ onSubmit, card, scores, onReset }: CommentBoxProps) {
const [comment, setComment] = useState<string>("");
// const [scores, setRubricScores] = useState<Record<string, number>>({});

const handleSubmit = () => {
onSubmit({ comment, card, scores});
setComment("");
onReset(); // Reset the scores after submission
};
export default function CommentBox({
onSubmit,
card,
scores,
onReset,
index,
}: CommentBoxProps) {
const [comment, setComment] = useState<string>("");
// const [scores, setRubricScores] = useState<Record<string, number>>({});

const handleSubmit = () => {
onSubmit({ comment, card, scores, index });
setComment("");
onReset(); // Reset the scores after submission
};

return (

<div className="my-12">
<div className="relative block">
return (
<div className="my-12">
<div className="relative block">
<label htmlFor="comment" className="mb-2 mt-4 block">
<FontAwesomeIcon
<FontAwesomeIcon
className="left-2 top-1/2 ml-2 h-[20px] w-[28px] cursor-pointer object-contain"
icon={faComment}
/>
Comments:
/>
Comments:
</label>
<textarea
id="comment"
className="h-32 w-full rounded border p-2"
value={comment}
onChange={(e) => setComment(e.target.value)}
placeholder="Add feedback here"
id="comment"
className="h-32 w-full rounded border p-2"
value={comment}
onChange={(e) => setComment(e.target.value)}
placeholder="Add feedback here"
></textarea>
</div>
<div className="flex justify-center mt-4">
<button
onClick={handleSubmit}
className="bg-blue-500 rounded bg-secondary px-4 py-2 text-white"
>
Submit
</button>
</div>
</div>
<div className="mt-4 flex justify-center">
<button
onClick={handleSubmit}
className="bg-blue-500 w-full rounded bg-secondary px-4 py-2 text-lg text-white"
>
Submit
</button>
</div>
</div>
);
}
);
}
4 changes: 2 additions & 2 deletions packages/web/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export const navLinks = [
title: "How to use",
},
{
id: "userFeedback",
title: "User Feedback",
id: "feedback",
title: "Feedback",
},
];

Expand Down
Loading

0 comments on commit 2cf56f7

Please sign in to comment.