= (props) => {
)}
- {/*
- ratePurchase(e)}
- >
- ☆
-
- ratePurchase(e)}
- >
- ☆
-
- ratePurchase(e)}
- >
- ☆
-
- ratePurchase(e)}
- >
- ☆
-
- ratePurchase(e)}
- >
- ☆
-
-
*/}
+
+ {/*
*/}
+
+
+
+
diff --git a/src/i18n/UI/English.ts b/src/i18n/UI/English.ts
index 6759651c..2e5d654d 100644
--- a/src/i18n/UI/English.ts
+++ b/src/i18n/UI/English.ts
@@ -136,6 +136,7 @@ export const English = {
editPost: "Edit",
getLinks: "Get Links",
checkoutAsGuest: "Checkout As Guest",
+ reviewResource: "Review",
},
messages: {
@@ -261,6 +262,16 @@ export const English = {
secular: "Secular",
resourceLinks: "Resource Links",
draft: "Draft",
+ whatDidYouThink: "What did you think?",
+ overallRating: "Overall Rating",
+ reviewQ1: "As described",
+ reviewQ2: "Age/grade appropriate",
+ reviewQ3: "Engaging",
+ reviewQ4: "High quality",
+ reviewQ5: "Easy to use/implement",
+ reviewQ6: "Fair price",
+ reviewTitle: "Review Title",
+ reviewText: "Review Text",
},
postLabels: {
@@ -271,6 +282,8 @@ export const English = {
slide: "Slide",
creatorProfileImage: "Creator Profile Image",
userProfileImage: "User Profile Image",
+ yourRating: "Your Rating",
+ reviews: "Reviews",
subtopics: "Topics",
},
diff --git a/src/i18n/UI/French.ts b/src/i18n/UI/French.ts
index f52acb4e..b34b7b08 100644
--- a/src/i18n/UI/French.ts
+++ b/src/i18n/UI/French.ts
@@ -133,6 +133,7 @@ export const French = {
editPost: "Editer",
getLinks: "Obtenir des Liens",
checkoutAsGuest: "Passer en tant qu'invite",
+ reviewResource: "Critique",
},
messages: {
@@ -263,6 +264,16 @@ export const French = {
secular: "Laïque",
resourceLinks: "Liens vers les ressources",
draft: "Brouillon",
+ whatDidYouThink: "Qu'en as-tu pensé?",
+ overallRating: "Note Globale",
+ reviewQ1: "Comme décrit",
+ reviewQ2: "Adapté à l'âge",
+ reviewQ3: "Engageante",
+ reviewQ4: "Haute qualité",
+ reviewQ5: "Facile à utiliser/mettre en œuvre",
+ reviewQ6: "Juste prix",
+ reviewTitle: "Titre de la Revue",
+ reviewText: "Texte de le Revue",
},
postLabels: {
@@ -273,6 +284,8 @@ export const French = {
slide: "Diapositive",
creatorProfileImage: "Image du profil du fournisseur",
userProfileImage: "Image du profil du user",
+ yourRating: "Votre Note",
+ reviews: "Critiques",
subtopics: "Sous-thèmes",
},
diff --git a/src/i18n/UI/Spanish.ts b/src/i18n/UI/Spanish.ts
index 797b85bc..2d694f54 100644
--- a/src/i18n/UI/Spanish.ts
+++ b/src/i18n/UI/Spanish.ts
@@ -136,6 +136,7 @@ export const Spanish = {
editPost: "Editar",
getLinks: "Obtener enlaces",
checkoutAsGuest: "Comprar como Invitado",
+ reviewResource: "Reseña",
},
messages: {
@@ -265,6 +266,16 @@ export const Spanish = {
secular: "Laico",
resourceLinks: "Enlaces de Recurso",
draft: "Borrador",
+ whatDidYouThink: "¿Qué pensó Ud?",
+ overallRating: "Calificación General",
+ reviewQ1: "Como se describe",
+ reviewQ2: "Apropiado para edad/grado",
+ reviewQ3: "Atractivo",
+ reviewQ4: "Alta calidad",
+ reviewQ5: "Fácil de usar/implementar",
+ reviewQ6: "Precio justo",
+ reviewTitle: "Títula de la Calificación",
+ reviewText: "Texto de la Calificación",
},
postLabels: {
@@ -275,6 +286,8 @@ export const Spanish = {
slide: "Diapositiva",
creatorProfileImage: "Imagen de Perfil del Proveedor",
userProfileImage: "Imagen de Perfil del Usere",
+ yourRating: "Tu Calificatión",
+ reviews: "Críticas",
subtopics: "Temas",
},
diff --git a/src/i18n/uiType.ts b/src/i18n/uiType.ts
index f10e50d3..fa966ff9 100644
--- a/src/i18n/uiType.ts
+++ b/src/i18n/uiType.ts
@@ -128,6 +128,7 @@ export interface uiObject {
editPost: string;
getLinks: string;
checkoutAsGuest: string;
+ reviewResource: string;
};
messages: {
@@ -240,6 +241,16 @@ export interface uiObject {
secular: string;
resourceLinks: string;
draft: string;
+ whatDidYouThink: string;
+ overallRating: string;
+ reviewQ1: string;
+ reviewQ2: string;
+ reviewQ3: string;
+ reviewQ4: string;
+ reviewQ5: string;
+ reviewQ6: string;
+ reviewTitle: string;
+ reviewText: string;
};
postLabels: {
@@ -250,6 +261,8 @@ export interface uiObject {
slide: string;
creatorProfileImage: string;
userProfileImage: string;
+ yourRating: string;
+ reviews: string;
subtopics: string;
};
diff --git a/src/lib/types.ts b/src/lib/types.ts
index d7d978e0..e5a7404b 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -79,4 +79,26 @@ export interface FilterPostsParams {
seller_id?: string;
from?: number;
to?: number;
-}
\ No newline at end of file
+}
+
+export interface Orders{
+ order_number: number;
+ order_date: number;
+ customer_id: number;
+ order_status: boolean;
+}
+
+export interface Order_Details{
+ order_number: number;
+ product_id: number;
+ quantity: number;
+}
+
+export interface Review{
+
+ resource_id : string,
+ reviewer_id: string,
+ review_title: string,
+ review_text: string,
+ overall_rating :number,
+}
diff --git a/src/pages/api/clientSubmitReviewResource.ts b/src/pages/api/clientSubmitReviewResource.ts
new file mode 100644
index 00000000..e790498d
--- /dev/null
+++ b/src/pages/api/clientSubmitReviewResource.ts
@@ -0,0 +1,134 @@
+
+import supabase from "../../lib/supabaseClientServer";
+import type { APIRoute } from "astro";
+import { useTranslations } from "@i18n/utils";
+
+export const POST: APIRoute = async ({ request, redirect }) => {
+
+ const formData = await request.formData();
+
+ //Just console.log the formData for troubleshooting
+ for (let pair of formData.entries()) {
+ console.log(pair[0] + ", " + pair[1]);
+ }
+
+ //Set internationalization values
+ const lang = formData.get("lang");
+ //@ts-ignore
+ const t = useTranslations(lang);
+
+ //set the formData fields to variables
+ const access_token = formData.get("access_token");
+ const refresh_token = formData.get("refresh_token");
+
+ const reviewTitle = formData.get("review_title");
+ const reviewText = formData.get("review_text");
+ const overallRating = formData.get("overall_rating");
+ const resourceId = formData.get("resource_id");
+ const userId = formData.get("user_id");
+
+
+
+ // Validate the formData makes sure none of the fields are blank. Could probably do more than this like check for invalid phone numbers, blank strings, unselected location info etc.
+
+ if (
+ !reviewTitle ||
+ !reviewText ||
+ !overallRating ||
+ !resourceId ||
+ !userId ||
+ access_token === ""
+ ) {
+ return new Response(
+ JSON.stringify({
+ message: t("apiErrors.missingFields"),
+ }),
+ { status: 500 }
+ );
+ }
+
+ //Get the session from supabase (for the server side) based on the access and refresh tokens
+ const { data: sessionData, error: sessionError } =
+ await supabase.auth.setSession({
+ refresh_token: refresh_token!.toString(),
+ access_token: access_token!.toString(),
+ });
+ if (sessionError) {
+ console.log("supabase error: " + sessionError.message);
+ return new Response(
+ JSON.stringify({
+ message: t("apiErrors.noSession"),
+ }),
+ { status: 500 }
+ );
+ }
+
+ console.log(sessionData);
+
+ //Make sure we have a session
+ if (!sessionData?.session) {
+ return new Response(
+ JSON.stringify({
+ message: t("apiErrors.noSession"),
+ }),
+ { status: 500 }
+ );
+ }
+
+ //Get the user and make sure we have a user
+ const user = sessionData?.session.user;
+
+ if (!user) {
+ return new Response(
+ JSON.stringify({
+ message: t("apiErrors.noUser"),
+ }),
+ { status: 500 }
+ );
+ }
+
+
+ let submission = {
+ resource_id: resourceId,
+ reviewer_id: userId,
+ review_title: reviewTitle,
+ review_text: reviewText,
+ overall_rating: overallRating,
+ };
+
+ const { error, data } = await supabase
+ .from("reviews")
+ .insert([submission])
+ .select();
+
+ if (error) {
+ console.log(error);
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.creatorCreateProfileError"),
+ //TODO: Internationalize
+ message: "fail to insert "
+ }),
+ { status: 500 }
+ );
+ } else if (!data) {
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.noProfileData"),
+ //TODO: Internationalize
+ message: "fail data fetch",
+ }),
+ { status: 500 }
+ );
+ } else {
+ console.log("Profile Data: " + JSON.stringify(data));
+ }
+
+ // If everything works send a success response
+ return new Response(
+ JSON.stringify({
+ message: t("apiErrors.success"),
+ }),
+ { status: 200 }
+ );
+};
diff --git a/src/pages/api/getAllReviews.ts b/src/pages/api/getAllReviews.ts
new file mode 100644
index 00000000..78792262
--- /dev/null
+++ b/src/pages/api/getAllReviews.ts
@@ -0,0 +1,46 @@
+
+import supabase from "../../lib/supabaseClientServer";
+import type { APIRoute } from "astro";
+import { useTranslations } from "@i18n/utils";
+import type { Review } from "@lib/types";
+
+export const POST: APIRoute = async ({ request, redirect }) => {
+ console.log(request)
+ const {
+ resource_id ,
+ } = await request.json()
+
+ const { error, data } = await supabase
+ .from("reviews")
+ .select("*")
+ .eq("resource_id",resource_id)
+
+ if (error) {
+ console.log(error);
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.creatorCreateProfileError"),
+ message:"fail to fetch"
+ }),
+ { status: 500 }
+ );
+ } else if (!data) {
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.noProfileData"),
+ message: "no data to fetch",
+ }),
+ { status: 500 }
+ );
+ } else {
+ console.log("Profile Data: " + JSON.stringify(data));
+ }
+
+ // If everything works send a success response
+ return new Response(
+ JSON.stringify({
+ body:data,
+ }),
+ { status: 200 }
+ );
+};
diff --git a/src/pages/api/getRatings.ts b/src/pages/api/getRatings.ts
new file mode 100644
index 00000000..d000d122
--- /dev/null
+++ b/src/pages/api/getRatings.ts
@@ -0,0 +1,41 @@
+import supabase from "../../lib/supabaseClientServer";
+import type { APIRoute } from "astro";
+import { useTranslations } from "@i18n/utils";
+import type { Review } from "@lib/types";
+
+export const POST: APIRoute = async ({ request, redirect }) => {
+ const { resource_id } = await request.json();
+
+ const { error, data } = await supabase
+ .from("reviews")
+ .select("overall_rating")
+ .eq("resource_id", resource_id);
+
+ if (error) {
+ console.log(error);
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.creatorCreateProfileError"),
+ message: "fail to fetch",
+ }),
+ { status: 500 }
+ );
+ } else if (!data) {
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.noProfileData"),
+ message: "no data to fetch",
+ }),
+ { status: 500 }
+ );
+ } else {
+ console.log("Review Data: ", JSON.stringify(data));
+ }
+
+ return new Response(
+ JSON.stringify({
+ body: data,
+ }),
+ { status: 200 }
+ );
+};
diff --git a/src/pages/api/getUserRating.ts b/src/pages/api/getUserRating.ts
new file mode 100644
index 00000000..d0197428
--- /dev/null
+++ b/src/pages/api/getUserRating.ts
@@ -0,0 +1,39 @@
+import supabase from "../../lib/supabaseClientServer";
+import type { APIRoute } from "astro";
+
+export const POST: APIRoute = async ({ request, redirect }) => {
+ const { reviewer_id, resource_id } = await request.json();
+
+ const { error, data } = await supabase
+ .from("reviews")
+ .select("overall_rating")
+ .match({ reviewer_id: reviewer_id, resource_id: resource_id });
+
+ if (error) {
+ console.log(error);
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.creatorCreateProfileError"),
+ message: "fail to fetch",
+ }),
+ { status: 500 }
+ );
+ } else if (!data) {
+ return new Response(
+ JSON.stringify({
+ // message: t("apiErrors.noProfileData"),
+ message: "no data to fetch",
+ }),
+ { status: 500 }
+ );
+ } else {
+ console.log("Review Data: ", JSON.stringify(data));
+ }
+
+ return new Response(
+ JSON.stringify({
+ body: data,
+ }),
+ { status: 200 }
+ );
+};
diff --git a/supabase/migrations/20240909194825_reviews.sql b/supabase/migrations/20240909194825_reviews.sql
new file mode 100644
index 00000000..dde00b00
--- /dev/null
+++ b/supabase/migrations/20240909194825_reviews.sql
@@ -0,0 +1,84 @@
+create table "public"."reviews" (
+ "id" bigint generated by default as identity not null,
+ "created_at" timestamp with time zone not null default now(),
+ "resource_id" bigint not null,
+ "reviewer_id" uuid not null,
+ "review_title" text,
+ "review_text" text,
+ "overall_rating" smallint not null
+);
+
+
+alter table "public"."reviews" enable row level security;
+
+CREATE UNIQUE INDEX reviews_pkey ON public.reviews USING btree (id);
+
+alter table "public"."reviews" add constraint "reviews_pkey" PRIMARY KEY using index "reviews_pkey";
+
+alter table "public"."reviews" add constraint "reviews_resource_id_fkey" FOREIGN KEY (resource_id) REFERENCES seller_post(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
+
+alter table "public"."reviews" validate constraint "reviews_resource_id_fkey";
+
+alter table "public"."reviews" add constraint "reviews_reviewer_id_fkey" FOREIGN KEY (reviewer_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
+
+alter table "public"."reviews" validate constraint "reviews_reviewer_id_fkey";
+
+grant delete on table "public"."reviews" to "anon";
+
+grant insert on table "public"."reviews" to "anon";
+
+grant references on table "public"."reviews" to "anon";
+
+grant select on table "public"."reviews" to "anon";
+
+grant trigger on table "public"."reviews" to "anon";
+
+grant truncate on table "public"."reviews" to "anon";
+
+grant update on table "public"."reviews" to "anon";
+
+grant delete on table "public"."reviews" to "authenticated";
+
+grant insert on table "public"."reviews" to "authenticated";
+
+grant references on table "public"."reviews" to "authenticated";
+
+grant select on table "public"."reviews" to "authenticated";
+
+grant trigger on table "public"."reviews" to "authenticated";
+
+grant truncate on table "public"."reviews" to "authenticated";
+
+grant update on table "public"."reviews" to "authenticated";
+
+grant delete on table "public"."reviews" to "service_role";
+
+grant insert on table "public"."reviews" to "service_role";
+
+grant references on table "public"."reviews" to "service_role";
+
+grant select on table "public"."reviews" to "service_role";
+
+grant trigger on table "public"."reviews" to "service_role";
+
+grant truncate on table "public"."reviews" to "service_role";
+
+grant update on table "public"."reviews" to "service_role";
+
+create policy "Enable insert for authenticated users only"
+on "public"."reviews"
+as permissive
+for insert
+to authenticated
+with check (true);
+
+
+create policy "Enable read access for all users"
+on "public"."reviews"
+as permissive
+for select
+to public
+using (true);
+
+
+
diff --git a/supabase/seed.sql b/supabase/seed.sql
index b0098e63..d1f69388 100644
--- a/supabase/seed.sql
+++ b/supabase/seed.sql
@@ -139,6 +139,17 @@ INSERT INTO "public"."location" ("id", "created_at", "street_number", "street_nu
(13, '2024-03-27 15:53:32.278633+00', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, 'b00f3d62-4eb1-40ba-b73e-e3dc78eff08a');
+-- Data for Name: orders; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+--INSERT INTO "public"."orders" ("order_number", "order_date", "customer_id", "order_status") VALUES
+-- ('51d1f510-f3e7-48c3-913d-05a1b499cc41', '2024-09-10 14:50:12.592153+00', 'a23376db-215d-49c4-9d9d-791c26579543', true);
+
+
+--
+-- Data for Name: order_details; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
--
-- Data for Name: profiles; Type: TABLE DATA; Schema: public; Owner: postgres
--
@@ -317,6 +328,30 @@ INSERT INTO "public"."users" ("user_id", "created_at", "display_name", "image_ur
('111d3bed-1c92-4cf5-a66f-2ecaf3e717c3', '2024-03-05 15:37:01.129356+00', NULL, NULL);
+--
+-- Data for Name: orders; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+INSERT INTO "public"."orders" ("order_number", "order_date", "customer_id", "order_status") VALUES
+ ('51d1f510-f3e7-48c3-913d-05a1b499cc41', '2024-09-10 14:50:12.592153+00', 'a23376db-215d-49c4-9d9d-791c26579543', true);
+
+
+--
+-- Data for Name: order_details; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+INSERT INTO "public"."order_details" ("order_number", "product_id", "quantity") VALUES
+ ('51d1f510-f3e7-48c3-913d-05a1b499cc41', 12, 2),
+ ('51d1f510-f3e7-48c3-913d-05a1b499cc41', 10, 2),
+ ('51d1f510-f3e7-48c3-913d-05a1b499cc41', 5, 1);
+
+
+-- Data for Name: reviews; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+INSERT INTO "public"."reviews" ("id", "created_at", "resource_id", "reviewer_id", "review_title", "review_text", "overall_rating") VALUES
+ (3, '2024-09-10 14:48:24.267324+00', 12, 'a23376db-215d-49c4-9d9d-791c26579543', 'test title', 'test review text', 4);
+
--
-- Name: refresh_tokens_id_seq; Type: SEQUENCE SET; Schema: auth; Owner: supabase_auth_admin
--
@@ -428,6 +463,9 @@ SELECT pg_catalog.setval('"public"."sellers_seller_id_seq"', 8, true);
SELECT pg_catalog.setval('"supabase_functions"."hooks_id_seq"', 1, true);
+--
+
+SELECT pg_catalog.setval('"public"."reviews_id_seq"', 4, true);
--
-- PostgreSQL database dump complete