Repository: abhi-kr-2100/Lingetic
Pull request #165: Add question lists to the frontend
Author: login: abhi-kr-2100
Created: 2025-04-10T11:00:55Z | Merged: 2025-04-10T11:32:32Z

- Update the user flow: language -> list -> questions
- Update the URLs to match the new flow
- Update the backend calls
- Modify unit tests accordingly

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a dedicated language page that displays tailored question lists for signed-in users.
  - Added new UI states (loading, empty, and error) to enhance the user experience during data fetching.
  - Launched components featuring a structured header and grid layout for presenting question lists.
  
- **Refactor**
  - Streamlined navigation links with simplified URL paths for more intuitive access to language content.
  - Updated component imports and parameters to align with new routing structures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx b/lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx
index ab2f61e7..9d74c377 100644
--- a/lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx
+++ b/lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx
@@ -1,5 +1,5 @@
 import { fireEvent, waitFor } from "@testing-library/react";
-import LearnPageComponent from "@/app/languages/learn/[language]/LearnPageComponent";
+import LearnPageComponent from "@/app/languages/[language]/[questionListId]/LearnPageComponent";
 import { renderWithQueryClient } from "@/utilities/testing-helpers";
 import type { FillInTheBlanksQuestion, Question } from "@/utilities/api-types";
 
@@ -8,7 +8,7 @@ global.fetch = jest.fn();
 const mockPush = jest.fn();
 jest.mock("next/navigation", () => ({
   useRouter: () => ({ push: mockPush }),
-  useParams: () => ({ language: "spanish" }),
+  useParams: () => ({ language: "spanish", questionListId: "1" }),
 }));
 
 describe("LearnPageComponent", () => {
diff --git a/lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx b/lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx
index 87f6c36b..6b7495a1 100644
--- a/lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx
+++ b/lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx
@@ -27,7 +27,7 @@ export default function LanguagePlayCard({
       <div className="p-4">
         <h2 className="text-xl font-semibold mb-2">{name}</h2>
         <Link
-          href={`/languages/learn/${id}`}
+          href={`/languages/${id}`}
           className="bg-skin-button-primary text-skin-inverted px-4 py-2 rounded transition-colors"
         >
           Play!
diff --git a/lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx b/lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx
index c9d6cbb3..0fea9bfb 100644
--- a/lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx
+++ b/lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx
@@ -7,7 +7,7 @@ interface LanguageCardProps {
 }
 
 export default function LanguageCard({ language }: LanguageCardProps) {
-  const url = `/languages/learn/${language.id}`;
+  const url = `/languages/${language.id}`;
 
   return (
     <Link href={url}>
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx b/lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx
new file mode 100644
index 00000000..acd26e67
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx
@@ -0,0 +1,30 @@
+import { BookOpen } from "lucide-react";
+import { useRouter } from "next/navigation";
+
+interface EmptyStateProps {
+  language: string;
+}
+
+export function EmptyState({ language }: EmptyStateProps) {
+  const router = useRouter();
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white flex items-center justify-center">
+      <div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full text-center">
+        <BookOpen className="h-12 w-12 text-[#2563eb] mx-auto mb-4" />
+        <h2 className="text-2xl font-bold text-[#374151] mb-2">
+          No Question Lists Available
+        </h2>
+        <p className="text-[#374151] mb-6">
+          {`We don't have any question lists for ${language} yet. Please check back later.`}
+        </p>
+        <button
+          onClick={() => router.push("/languages")}
+          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
+        >
+          Back to Languages
+        </button>
+      </div>
+    </div>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx b/lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx
new file mode 100644
index 00000000..9377faf6
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx
@@ -0,0 +1,24 @@
+import { XCircle } from "lucide-react";
+import { useRouter } from "next/navigation";
+
+export function ErrorState() {
+  const router = useRouter();
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white flex items-center justify-center">
+      <div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full text-center">
+        <XCircle className="h-12 w-12 text-[#dc2626] mx-auto mb-4" />
+        <h2 className="text-2xl font-bold text-[#374151] mb-2">Oops!</h2>
+        <p className="text-[#374151] mb-6">
+          {"We couldn't load question lists. Please try again later."}
+        </p>
+        <button
+          onClick={() => router.push("/languages")}
+          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
+        >
+          Back to Languages
+        </button>
+      </div>
+    </div>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx b/lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx
new file mode 100644
index 00000000..167a8dcc
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx
@@ -0,0 +1,12 @@
+import { Loader2 } from "lucide-react";
+
+export function LoadingState() {
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white flex items-center justify-center">
+      <div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full text-center">
+        <Loader2 className="h-12 w-12 text-[#2563eb] animate-spin mx-auto mb-4" />
+        <p className="text-[#374151] text-lg">Loading question lists...</p>
+      </div>
+    </div>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx b/lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx
new file mode 100644
index 00000000..9c752f34
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import { useParams } from "next/navigation";
+import { LoadingState } from "./LoadingState";
+import { ErrorState } from "./ErrorState";
+import { EmptyState } from "./EmptyState";
+import { QuestionListGrid } from "./QuestionListGrid";
+import { QuestionListHeader } from "./QuestionListHeader";
+import useQuestionLists from "./useQuestionLists";
+
+export default function QuestionListComponent() {
+  const params = useParams();
+  const language = params.language as string;
+  const result = useQuestionLists({ language });
+
+  if (result.isLoading) return <LoadingState />;
+  if (result.isError) return <ErrorState />;
+  if (!result.hasLists || result.lists.length === 0)
+    return <EmptyState language={language} />;
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white p-8">
+      <div className="max-w-4xl mx-auto">
+        <QuestionListHeader language={language} />
+        <QuestionListGrid questionLists={result.lists} language={language} />
+      </div>
+    </div>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx b/lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx
new file mode 100644
index 00000000..4474ba6a
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx
@@ -0,0 +1,30 @@
+import { useRouter } from "next/navigation";
+import type { QuestionList } from "@/utilities/api-types";
+
+interface QuestionListGridProps {
+  questionLists: QuestionList[];
+  language: string;
+}
+
+export function QuestionListGrid({
+  questionLists,
+  language,
+}: QuestionListGridProps) {
+  const router = useRouter();
+
+  return (
+    <div className="grid gap-4">
+      {questionLists.map((list: QuestionList) => (
+        <button
+          key={list.id}
+          onClick={() => router.push(`/languages/${language}/${list.id}`)}
+          className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
+        >
+          <h2 className="text-xl font-semibold text-[#374151] mb-2">
+            {list.name}
+          </h2>
+        </button>
+      ))}
+    </div>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx b/lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx
new file mode 100644
index 00000000..d702ec5d
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx
@@ -0,0 +1,13 @@
+interface QuestionListHeaderProps {
+  language: string;
+}
+
+export function QuestionListHeader({ language }: QuestionListHeaderProps) {
+  return (
+    <div className="flex items-center justify-between mb-8">
+      <h1 className="text-3xl font-bold text-[#374151]">
+        Question Lists for <span className="text-[#2563eb]">{language}</span>
+      </h1>
+    </div>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/learn/[language]/LearnPageComponent.tsx b/lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx
similarity index 96%
rename from lingetic-nextjs-frontend/app/languages/learn/[language]/LearnPageComponent.tsx
rename to lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx
index 75d5d50c..6307decb 100644
--- a/lingetic-nextjs-frontend/app/languages/learn/[language]/LearnPageComponent.tsx
+++ b/lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx
@@ -10,14 +10,16 @@ import type { FillInTheBlanksQuestion, Question } from "@/utilities/api-types";
 import type QuestionProps from "@/app/components/questions/QuestionProps";
 
 export default function LearnPageComponent() {
-  const { language } = useParams<LearnPageParams>();
+  const { language, questionListId } = useParams<LearnPageParams>();
   assert(language.trim().length > 0, "language is required");
+  assert(questionListId.trim().length > 0, "questionListId is required");
 
   const router = useRouter();
   const nextButtonRef = useRef<HTMLButtonElement>(null);
 
   const result = useQuestions({
     language,
+    questionListId,
     onFinish: () => {
       router.push("/languages");
     },
@@ -116,6 +118,7 @@ export default function LearnPageComponent() {
 
 interface LearnPageParams {
   language: string;
+  questionListId: string;
 
   // Not used, but required by useParams
   [key: string]: string;
diff --git a/lingetic-nextjs-frontend/app/languages/learn/[language]/page.tsx b/lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/page.tsx
similarity index 100%
rename from lingetic-nextjs-frontend/app/languages/learn/[language]/page.tsx
rename to lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/page.tsx
diff --git a/lingetic-nextjs-frontend/app/languages/learn/[language]/useQuestions.ts b/lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts
similarity index 90%
rename from lingetic-nextjs-frontend/app/languages/learn/[language]/useQuestions.ts
rename to lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts
index a32ba46e..6bb70a2d 100644
--- a/lingetic-nextjs-frontend/app/languages/learn/[language]/useQuestions.ts
+++ b/lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts
@@ -8,6 +8,7 @@ import { useAuth } from "@clerk/nextjs";
 interface UseQuestionsParams {
   onFinish: () => void;
   language: string;
+  questionListId: string;
 }
 
 interface LoadingState {
@@ -46,8 +47,10 @@ type UseQuestionsResult =
 export default function useQuestions({
   onFinish,
   language,
+  questionListId,
 }: UseQuestionsParams): UseQuestionsResult {
   assert(language.trim().length > 0, "language is required");
+  assert(questionListId.trim().length > 0, "questionListId is required");
 
   const { getToken } = useAuth();
 
@@ -56,8 +59,8 @@ export default function useQuestions({
     isLoading,
     isError,
   } = useQuery({
-    queryKey: ["questions", language],
-    queryFn: () => fetchQuestions(language, getToken),
+    queryKey: ["questions", language, questionListId],
+    queryFn: () => fetchQuestions(language, questionListId, getToken),
 
     // The same questions should not be displayed on different renders
     // of the component. This is because the questions that Lingetic thinks
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/page.tsx b/lingetic-nextjs-frontend/app/languages/[language]/page.tsx
new file mode 100644
index 00000000..7a9852d2
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/page.tsx
@@ -0,0 +1,17 @@
+"use client";
+
+import { RedirectToSignIn, SignedIn, SignedOut } from "@clerk/nextjs";
+import QuestionListComponent from "./QuestionListComponent";
+
+export default function LanguagePage() {
+  return (
+    <>
+      <SignedIn>
+        <QuestionListComponent />
+      </SignedIn>
+      <SignedOut>
+        <RedirectToSignIn />
+      </SignedOut>
+    </>
+  );
+}
diff --git a/lingetic-nextjs-frontend/app/languages/[language]/useQuestionLists.ts b/lingetic-nextjs-frontend/app/languages/[language]/useQuestionLists.ts
new file mode 100644
index 00000000..10d40ed9
--- /dev/null
+++ b/lingetic-nextjs-frontend/app/languages/[language]/useQuestionLists.ts
@@ -0,0 +1,70 @@
+import { useQuery } from "@tanstack/react-query";
+import { fetchQuestionLists } from "@/utilities/api";
+import assert from "@/utilities/assert";
+import type { QuestionList } from "@/utilities/api-types";
+import { useAuth } from "@clerk/nextjs";
+
+interface UseQuestionListsParams {
+  language: string;
+}
+
+interface LoadingState {
+  isLoading: true;
+  isError: false;
+  hasLists: false;
+}
+
+interface ErrorState {
+  isLoading: false;
+  isError: true;
+  hasLists: false;
+}
+
+interface SuccessState {
+  isLoading: false;
+  isError: false;
+  hasLists: true;
+  lists: QuestionList[];
+}
+
+type UseQuestionListsResult = LoadingState | ErrorState | SuccessState;
+
+export default function useQuestionLists({
+  language,
+}: UseQuestionListsParams): UseQuestionListsResult {
+  assert(language.trim().length > 0, "language is required");
+  const { getToken } = useAuth();
+
+  const {
+    data: lists = [],
+    isLoading,
+    isError,
+  } = useQuery({
+    queryKey: ["questionLists", language],
+    queryFn: () => fetchQuestionLists(language, getToken),
+    refetchOnWindowFocus: true,
+  });
+
+  if (isLoading) {
+    return {
+      isLoading: true,
+      isError: false,
+      hasLists: false,
+    };
+  }
+
+  if (isError) {
+    return {
+      isLoading: false,
+      isError: true,
+      hasLists: false,
+    };
+  }
+
+  return {
+    isLoading: false,
+    isError: false,
+    hasLists: true,
+    lists,
+  };
+}
\ No newline at end of file
diff --git a/lingetic-nextjs-frontend/utilities/api-types.ts b/lingetic-nextjs-frontend/utilities/api-types.ts
index fe508418..ba59faed 100644
--- a/lingetic-nextjs-frontend/utilities/api-types.ts
+++ b/lingetic-nextjs-frontend/utilities/api-types.ts
@@ -29,3 +29,9 @@ export interface AttemptResponse {
 export interface FillInTheBlanksAttemptResponse extends AttemptResponse {
   correctAnswer: string;
 }
+
+export interface QuestionList {
+  id: string;
+  name: string;
+  language: string;
+}
diff --git a/lingetic-nextjs-frontend/utilities/api.ts b/lingetic-nextjs-frontend/utilities/api.ts
index a4226aad..05be0f7e 100644
--- a/lingetic-nextjs-frontend/utilities/api.ts
+++ b/lingetic-nextjs-frontend/utilities/api.ts
@@ -1,4 +1,9 @@
-import type { AttemptResponse, Question, AttemptRequest } from "./api-types";
+import type {
+  AttemptResponse,
+  Question,
+  AttemptRequest,
+  QuestionList,
+} from "./api-types";
 import assert from "./assert";
 
 async function fetchOrThrow<T>(url: string, options?: RequestInit): Promise<T> {
@@ -19,7 +24,7 @@ export async function attemptQuestion<T extends AttemptResponse>(
   assert(token !== null, "Token was null when attempting question");
 
   return await fetchOrThrow(
-    `${process.env.NEXT_PUBLIC_API_BASE_URL}/questions/attempt`,
+    `${process.env.NEXT_PUBLIC_API_BASE_URL}/language-test-service/questions/attempt`,
     {
       method: "POST",
       headers: {
@@ -31,19 +36,43 @@ export async function attemptQuestion<T extends AttemptResponse>(
   );
 }
 
+export async function fetchQuestionLists(
+  language: string,
+  getToken: () => Promise<string | null>
+): Promise<QuestionList[]> {
+  assert(language.trim().length > 0, "language is required");
+
+  const token = await getToken();
+  assert(token !== null, "Token was null when fetching question lists");
+
+  const encodedLanguage = encodeURIComponent(language);
+
+  return await fetchOrThrow(
+    `${process.env.NEXT_PUBLIC_API_BASE_URL}/language-test-service/lists?language=${encodedLanguage}`,
+    {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    }
+  );
+}
+
 export async function fetchQuestions(
   language: string,
+  questionListId: string,
   getToken: () => Promise<string | null>
 ): Promise<Question[]> {
   assert(language.trim().length > 0, "language is required");
+  assert(questionListId.trim().length > 0, "questionListId is required");
 
   const token = await getToken();
   assert(token !== null, "Token was null when fetching questions");
 
   const encodedLanguage = encodeURIComponent(language);
+  const encodedQuestionListId = encodeURIComponent(questionListId);
 
   return await fetchOrThrow(
-    `${process.env.NEXT_PUBLIC_API_BASE_URL}/questions?language=${encodedLanguage}`,
+    `${process.env.NEXT_PUBLIC_API_BASE_URL}/language-test-service/questions?language=${encodedLanguage}&questionListId=${encodedQuestionListId}`,
     {
       headers: {
         Authorization: `Bearer ${token}`,


Reviews:
user: login: gemini-code-assist[bot]
body: Hello @abhi-kr-2100, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

## Summary of Changes
This pull request introduces question lists to the frontend, updating the user flow to navigate from language selection to question lists before accessing the questions themselves. The URLs have been updated to reflect this new flow, and corresponding changes have been made to backend calls and unit tests. Specifically, the route `/languages/learn/:language` is changed to `/languages/:language` which now displays a list of available question lists for that language. Selecting a question list will then take the user to the learning component at `/languages/:language/:questionListId`.

### Highlights
* **Route Update**: The primary navigation flow has been updated from `language -> questions` to `language -> question list -> questions`.
* **URL Structure**: URLs are updated to reflect the new flow, using `/languages/:language` for language selection and `/languages/:language/:questionListId` for specific question lists.
* **New Components**: Introduction of new components like `QuestionListComponent`, `QuestionListGrid`, `QuestionListHeader`, `LoadingState`, `ErrorState`, and `EmptyState` to manage and display question lists.
* **API Integration**: Backend calls are updated to fetch question lists and questions based on the selected language and question list ID.
* **Error Handling**: Added `ErrorState`, `EmptyState`, and `LoadingState` components to handle different scenarios when fetching question lists.

### Changelog
<details>
<summary>Click here to see the changelog</summary>

* **lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx**
  * Updated import path for `LearnPageComponent` to reflect the new URL structure (line 2).
  * Updated `useParams` mock to include `questionListId` (line 11).
* **lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx**
  * Updated the `href` for the play button to navigate to the question list page for a language (line 30).
* **lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx**
  * Updated the URL to navigate to the question list page for a language (line 10).
* **lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx**
  * Created a new component to display when no question lists are available for a selected language.
  * Includes a button to navigate back to the languages page (lines 1-30).
* **lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx**
  * Created a new component to display when there is an error loading question lists.
  * Includes a button to navigate back to the languages page (lines 1-24).
* **lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx**
  * Created a new component to display a loading state while fetching question lists (lines 1-12).
* **lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx**
  * Created a new component to fetch and display a list of question lists for a given language.
  * Handles loading, error, and empty states (lines 1-51).
* **lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx**
  * Created a new component to display question lists in a grid format.
  * Each item navigates to the learning page for the specific question list (lines 1-30).
* **lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx**
  * Created a header component for the question list page, displaying the language name (lines 1-13).
* **lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx**
  * Updated to retrieve `questionListId` from `useParams` (line 13).
  * Added assertion to ensure `questionListId` is present (line 15).
  * Passed `questionListId` to the `useQuestions` hook (line 22).
  * Updated `LearnPageParams` interface to include `questionListId` (line 121).
* **lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts**
  * Updated `UseQuestionsParams` interface to include `questionListId` (line 11).
  * Added assertion to ensure `questionListId` is present (line 53).
  * Updated `useQuery` hook to include `questionListId` in the query key (line 62).
  * Updated `fetchQuestions` call to include `questionListId` (line 63).
* **lingetic-nextjs-frontend/app/languages/[language]/page.tsx**
  * Created a new page component to render the QuestionListComponent (lines 1-17).
* **lingetic-nextjs-frontend/utilities/api-types.ts**
  * Added a new interface `QuestionList` to represent question list data (lines 33-37).
* **lingetic-nextjs-frontend/utilities/api.ts**
  * Updated API base URL for attempt question and fetch questions (lines 27, 51, 75).
  * Added a new function `fetchQuestionLists` to fetch question lists for a given language (lines 39-58).
  * Updated `fetchQuestions` to accept `questionListId` as a parameter (line 62).
  * Updated `fetchQuestions` to include `questionListId` in the API call (line 75).

</details>


<details>

<summary><b>Using Gemini Code Assist</b></summary>
<br>

The full guide for Gemini Code Assist can be found on our [documentation page](https://developers.google.com/gemini-code-assist/docs/review-github-code), here are some quick tips.

<b>Invoking Gemini</b>

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either `/gemini <command>` or `@gemini-code-assist <command>`. Below is a summary of the supported commands.

Feature | Command | Description
--- | --- | ---
Code Review | `/gemini review` | Performs a code review for the current pull request in its current state.
Pull Request Summary | `/gemini summary` | Provides a summary of the current pull request in its current state.
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments.
Help | `/gemini help` | Displays a list of available commands.

<b>Customization</b>

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a `.gemini/` folder in the base of the repository. Detailed instructions can be found [here](https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github).

<b>Limitations & Feedback</b>

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments to provide feedback.

</details>

<b>You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the [Gemini Code Assist IDE Extension](https://cloud.google.com/products/gemini/code-assist).</b>


[^1]: Review the [Privacy Notices](https://policies.google.com/privacy), [Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy), [Terms of Service](https://policies.google.com/terms), and learn how to configure Gemini Code Assist in GitHub [here](https://developers.google.com/gemini-code-assist/docs/review-github-code). Gemini can make mistakes, so double check it and [use code with caution](https://support.google.com/legal/answer/13505487).

---

> A list of questions,
> A path to knowledge starts,
> New routes we explore.


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-10T11:01:09Z
user: login: gemini-code-assist[bot]
body: ## Code Review
The pull request introduces a new user flow that includes question lists, updates URLs, modifies backend calls, and updates unit tests. Overall, the changes seem well-structured and address the intended functionality. However, there are a few areas that could be improved for better clarity and maintainability.

### Summary of Findings
* **Missing Error Handling in `fetchQuestionLists`**: The `fetchQuestionLists` function in `utilities/api.ts` lacks specific error handling for different HTTP status codes. This could lead to unexpected behavior if the API returns a non-200 status code.
* **Inconsistent Naming**: The naming of the `LanguagePage` component might be misleading as it now displays a list of question lists rather than a page directly related to the language itself. Consider renaming it to better reflect its current functionality.
* **Duplicated Styling**: The styling for the loading, error, and empty states are duplicated across multiple components. Consider creating a reusable component or utility function to handle these common styles.

### Merge Readiness
The pull request is almost ready for merging. Addressing the missing error handling in `fetchQuestionLists` is crucial. While the other suggestions are not critical, they would improve the overall quality and maintainability of the code. I am unable to directly approve this pull request, and recommend that others review and approve this code before merging. However, I recommend that the pull request not be merged until the high severity issues are addressed.
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-04-10T11:01:29Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 5**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx (1)</summary><blockquote>

`105-112`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Verify mock responses for the updated API endpoint**

The mock responses used in tests should align with the updated API endpoint that now includes questionListId.


Run the following script to check if the mock implementation matches the updated fetchQuestions function signature:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if fetchQuestions implementation in the API utilities matches the test mocks

# Find the fetchQuestions implementation
rg -A 5 "export async function fetchQuestions" --type=ts

# Compare with the mock implementation in tests
rg -A 10 "mockSuccessfulFetch" --type=ts
```

Length of output: 7046

---



</details>

**Action Required: Update Test Mocks for New API Parameter**

It appears that the updated API endpoint now requires a `questionListId` parameter, as confirmed by the signature of `fetchQuestions` in `lingetic-nextjs-frontend/utilities/api.ts`. However, the current test mock `mockSuccessfulFetch` in `lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx` only returns a generic JSON response and doesn’t account for the additional parameter.

- Please update the mock implementation so that it aligns with the `fetchQuestions` function signature (i.e. include handling for `questionListId`).
- Verify that any tests exercising this API call pass an appropriate dummy or expected value for `questionListId`.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d4c72c93dd9428bc65d4413f976d006de349998d and 194b9a480de60a2216cbeb1165d9c184d6b4f9c7.

</details>

<details>
<summary>📒 Files selected for processing (14)</summary>

* `lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx` (2 hunks)
* `lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx` (1 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx` (2 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts` (3 hunks)
* `lingetic-nextjs-frontend/app/languages/[language]/page.tsx` (1 hunks)
* `lingetic-nextjs-frontend/utilities/api-types.ts` (1 hunks)
* `lingetic-nextjs-frontend/utilities/api.ts` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (6)</summary>

<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/page.tsx (1)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx (1)</summary>

* `QuestionListComponent` (14-51)

</details>

</blockquote></details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx (1)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/utilities/api-types.ts (1)</summary>

* `QuestionList` (33-37)

</details>

</blockquote></details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx (2)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/utilities/assert.ts (1)</summary>

* `assert` (3-13)

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts (1)</summary>

* `useQuestions` (47-118)

</details>

</blockquote></details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts (2)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/utilities/assert.ts (1)</summary>

* `assert` (3-13)

</details>
<details>
<summary>lingetic-nextjs-frontend/utilities/api.ts (1)</summary>

* `fetchQuestions` (60-82)

</details>

</blockquote></details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx (2)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/utilities/api-types.ts (1)</summary>

* `QuestionList` (33-37)

</details>
<details>
<summary>lingetic-nextjs-frontend/utilities/api.ts (1)</summary>

* `fetchQuestionLists` (39-58)

</details>

</blockquote></details>
<details>
<summary>lingetic-nextjs-frontend/utilities/api.ts (2)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/utilities/api-types.ts (2)</summary>

* `QuestionList` (33-37)
* `Question` (4-7)

</details>
<details>
<summary>lingetic-nextjs-frontend/utilities/assert.ts (1)</summary>

* `assert` (3-13)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx</summary>

[error] 15-18: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx</summary>

[error] 18-22: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx</summary>

[error] 21-24: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Codacy Static Code Analysis

</details>

<details>
<summary>🔇 Additional comments (24)</summary><blockquote>

<details>
<summary>lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx (1)</summary>

`10-10`: **URL path structure updated correctly**

The URL construction has been simplified by removing the `/learn/` segment, which aligns with the new user flow described in the PR objectives. This change is consistent with similar modifications in `LanguagePlayCard.tsx`.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx (1)</summary>

`30-30`: **URL path simplified consistently**

The Link's href attribute has been updated to remove the `learn` segment, maintaining consistency with the changes made in `LanguageCard.tsx`. This standardized URL structure supports the new user flow from language selection to question lists.

</details>
<details>
<summary>lingetic-nextjs-frontend/utilities/api-types.ts (1)</summary>

`33-37`: **Well-structured QuestionList interface added**

The new `QuestionList` interface provides the necessary type definition to support the question lists feature, with appropriate properties for identification, naming, and language association. This addition aligns with the PR objective of introducing a list view in the user flow.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx (1)</summary>

`1-12`: **Well-implemented loading state component**

The LoadingState component provides clear visual feedback to users while question lists are being fetched. The design uses appropriate styling with a gradient background, centered content, and an animated spinner for a polished user experience.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/page.tsx (1)</summary>

`1-17`: **Authentication integration looks good.**

The component correctly implements Clerk's authentication flow with conditional rendering based on authentication status. The use of `SignedIn` and `SignedOut` components ensures proper access control, while the `RedirectToSignIn` component provides a smooth authentication experience.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx (1)</summary>

`7-24`: **Error state UI implementation looks good.**

The component provides clear visual feedback with an appropriate icon, message, and action button. The styling and user experience considerations are well-implemented.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 15-18: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx (1)</summary>

`4-7`: **Props interface is well-defined.**

Good job defining a clear interface for the component props with appropriate types.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx (1)</summary>

`1-13`: **Header component implementation looks good.**

The component is simple, focused, and follows good practices with proper typing of props and clear presentation of the language context.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx (3)</summary>

`13-15`: **Properly implemented parameter handling**

The component correctly extracts and validates both the `language` and new `questionListId` parameters from the URL. The assertions ensure that the required parameters are present before processing.

---

`22-22`: **Parameter correctly passed to useQuestions hook**

The `questionListId` parameter is appropriately forwarded to the `useQuestions` hook, maintaining consistency with the updated hook signature.

---

`119-125`: **Interface properly updated to include new parameter**

The `LearnPageParams` interface has been correctly updated to include the new `questionListId` field, ensuring type safety when extracting parameters from the URL.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts (3)</summary>

`8-12`: **Interface correctly updated with new parameter**

The `UseQuestionsParams` interface has been properly updated to include the required `questionListId` parameter, maintaining type safety throughout the component.

---

`47-53`: **Function signature and validation properly updated**

The function signature has been updated to include `questionListId` in the destructured parameters, and the assertion ensures that it's not empty before proceeding with the API call.

---

`62-63`: **Query configuration correctly updated**

The `queryKey` array and `queryFn` have been updated to incorporate the `questionListId` parameter, ensuring proper cache management and API interaction.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx (2)</summary>

`4-6`: **Well-defined props interface**

The component has a clear, simple props interface that correctly specifies the required `language` parameter.

---

`8-30`: **Clean component implementation**

The EmptyState component is well-structured with appropriate styling and messaging. It correctly displays the dynamic language value and provides a way for users to navigate back.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 21-24: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

</details>
<details>
<summary>lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx (2)</summary>

`2-2`: **Import path correctly updated**

The import path for LearnPageComponent has been properly updated to reflect the new directory structure that includes the questionListId parameter.

---

`11-11`: **Mock parameters correctly updated**

The useParams mock now correctly returns both the language and questionListId parameters, ensuring the tests align with the updated component expectations.

</details>
<details>
<summary>lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx (2)</summary>

`1-21`: **Well-structured component with clear state management**

The component follows React best practices with proper imports, state management, and parameter extraction from the URL. The use of Clerk for authentication and Next.js navigation hooks is well-implemented.

---

`39-51`: **Effective conditional rendering pattern**

The component follows the recommended pattern for handling async data in React with distinct handling for loading, error, and empty states. The UI structure with gradient background and proper container sizing is well-designed.

</details>
<details>
<summary>lingetic-nextjs-frontend/utilities/api.ts (4)</summary>

`1-6`: **Appropriate type import addition**

Adding the QuestionList type to the imports is necessary to support the new question list functionality.

---

`27-27`: **API endpoint updated for service organization**

The URL path update to include '/language-test-service/' appears to be part of a systematic API restructuring to better organize endpoints by service.

---

`39-58`: **Well-implemented question lists fetch function**

The new fetchQuestionLists function follows the established pattern for API calls in this codebase with proper parameter validation, error handling, and authentication. The function correctly returns a Promise of QuestionList array and encodes parameters for URL safety.

---

`60-76`: **Appropriate modifications to fetchQuestions function**

The addition of the questionListId parameter and associated validation, encoding, and URL construction is properly implemented. These changes align with the new application flow that transitions from language selection to question lists to individual questions.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-10T11:04:06Z

Review comments:
diff_hunk: @@ -31,19 +36,43 @@ export async function attemptQuestion<T extends AttemptResponse>(
   );
 }
 
+export async function fetchQuestionLists(
+  language: string,
+  getToken: () => Promise<string | null>
+): Promise<QuestionList[]> {
+  assert(language.trim().length > 0, "language is required");
+
+  const token = await getToken();
+  assert(token !== null, "Token was null when fetching question lists");
+
+  const encodedLanguage = encodeURIComponent(language);
+
+  return await fetchOrThrow(
+    `${process.env.NEXT_PUBLIC_API_BASE_URL}/language-test-service/lists?language=${encodedLanguage}`,
+    {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    }
path: lingetic-nextjs-frontend/utilities/api.ts
user: login: gemini-code-assist[bot]
body: ![high](https://img.shields.io/badge/priority-high-orange)

Consider adding more specific error handling based on the HTTP status code. For example, you could check for 404 errors and display a more informative message to the user. This will improve the user experience and make it easier to debug issues in production.

```suggestion
  const response = await fetch(url, options);
  if (!response.ok) {
    if (response.status === 404) {
      throw new Error(`Question lists not found for language: ${language}`);
    }
    throw new Error(response.statusText);
  }
  return response.json();
```
created_at: 2025-04-10T11:01:29Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+"use client";
+
+import { RedirectToSignIn, SignedIn, SignedOut } from "@clerk/nextjs";
+import QuestionListComponent from "./QuestionListComponent";
+
+export default function LanguagePage() {
path: lingetic-nextjs-frontend/app/languages/[language]/page.tsx
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

Given that this page now displays a list of question lists, a more descriptive name might be `QuestionListsPage` or `LanguageQuestionListsPage` to better reflect its content.

```typescript
export default function QuestionListsPage() {
```
created_at: 2025-04-10T11:01:29Z
author_association: NONE
diff_hunk: @@ -0,0 +1,51 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useAuth } from "@clerk/nextjs";
+import { useParams } from "next/navigation";
+import { fetchQuestionLists } from "@/utilities/api";
+import type { QuestionList } from "@/utilities/api-types";
+import { LoadingState } from "./LoadingState";
+import { ErrorState } from "./ErrorState";
+import { EmptyState } from "./EmptyState";
+import { QuestionListGrid } from "./QuestionListGrid";
+import { QuestionListHeader } from "./QuestionListHeader";
+
+export default function QuestionListComponent() {
+  const params = useParams();
+  const language = params.language as string;
+  const [questionLists, setQuestionLists] = useState<QuestionList[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(false);
+  const { getToken } = useAuth();
+
+  useEffect(() => {
+    const fetchLists = async () => {
+      try {
+        const lists = await fetchQuestionLists(language, getToken);
+        setQuestionLists(lists);
+        setError(false);
+      } catch (err) {
+        console.error("Error fetching question lists:", err);
+        setError(true);
path: lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

Consider using a more specific type for the error.  What is the type of `err` here?

```typescript
      } catch (err: any) {
```
created_at: 2025-04-10T11:01:29Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { BookOpen } from "lucide-react";
+import { useRouter } from "next/navigation";
+
+interface EmptyStateProps {
+  language: string;
+}
+
+export function EmptyState({ language }: EmptyStateProps) {
+  const router = useRouter();
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white flex items-center justify-center">
+      <div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full text-center">
+        <BookOpen className="h-12 w-12 text-[#2563eb] mx-auto mb-4" />
+        <h2 className="text-2xl font-bold text-[#374151] mb-2">
+          No Question Lists Available
+        </h2>
+        <p className="text-[#374151] mb-6">
+          {`We don't have any question lists for ${language} yet. Please check back later.`}
+        </p>
+        <button
+          onClick={() => router.push("/languages")}
+          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
+        >
+          Back to Languages
+        </button>
+      </div>
+    </div>
path: lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

The styling for the empty state is duplicated in `ErrorState.tsx` and `LoadingState.tsx`. Consider creating a reusable component or utility function to handle these common styles. This will make the code more maintainable and easier to update in the future.

```typescript
import { CommonState } from "@/app/components/CommonState";

// ...

  return (
    <CommonState
      icon={<BookOpen className="h-12 w-12 text-[#2563eb] mx-auto mb-4" />}
      title="No Question Lists Available"
      message={`We don't have any question lists for ${language} yet. Please check back later.`}
      buttonText="Back to Languages"
      onClick={() => router.push("/languages")}
    />
  );
```
created_at: 2025-04-10T11:01:29Z
author_association: NONE
diff_hunk: @@ -0,0 +1,24 @@
+import { XCircle } from "lucide-react";
+import { useRouter } from "next/navigation";
+
+export function ErrorState() {
+  const router = useRouter();
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white flex items-center justify-center">
+      <div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full text-center">
+        <XCircle className="h-12 w-12 text-[#dc2626] mx-auto mb-4" />
+        <h2 className="text-2xl font-bold text-[#374151] mb-2">Oops!</h2>
+        <p className="text-[#374151] mb-6">
+          {"We couldn't load question lists. Please try again later."}
+        </p>
+        <button
+          onClick={() => router.push("/languages")}
+          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
+        >
+          Back to Languages
+        </button>
path: lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add button type for accessibility.**

The button element should have an explicit type attribute to improve accessibility and prevent unexpected form submission behavior.


```diff
<button
+  type="button"
  onClick={() => router.push("/languages")}
  className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
>
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        <button
          type="button"
          onClick={() => router.push("/languages")}
          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
        >
          Back to Languages
        </button>
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 15-18: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-10T11:04:04Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { useRouter } from "next/navigation";
+import type { QuestionList } from "@/utilities/api-types";
+
+interface QuestionListGridProps {
+  questionLists: QuestionList[];
+  language: string;
+}
+
+export function QuestionListGrid({
+  questionLists,
+  language,
+}: QuestionListGridProps) {
+  const router = useRouter();
+
+  return (
+    <div className="grid gap-4">
+      {questionLists.map((list: QuestionList) => (
+        <button
+          key={list.id}
+          onClick={() => router.push(`/languages/${language}/${list.id}`)}
+          className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
+        >
+          <h2 className="text-xl font-semibold text-[#374151] mb-2">
+            {list.name}
+          </h2>
+        </button>
path: lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add button type for accessibility.**

The button element should have an explicit type attribute to improve accessibility and prevent unexpected form submission behavior when inside forms.


```diff
<button
+  type="button"
  key={list.id}
  onClick={() => router.push(`/languages/${language}/${list.id}`)}
  className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
>
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        <button
          type="button"
          key={list.id}
          onClick={() => router.push(`/languages/${language}/${list.id}`)}
          className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
        >
          <h2 className="text-xl font-semibold text-[#374151] mb-2">
            {list.name}
          </h2>
        </button>
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 18-22: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-10T11:04:05Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { useRouter } from "next/navigation";
+import type { QuestionList } from "@/utilities/api-types";
+
+interface QuestionListGridProps {
+  questionLists: QuestionList[];
+  language: string;
+}
+
+export function QuestionListGrid({
+  questionLists,
+  language,
+}: QuestionListGridProps) {
+  const router = useRouter();
+
+  return (
+    <div className="grid gap-4">
+      {questionLists.map((list: QuestionList) => (
+        <button
+          key={list.id}
+          onClick={() => router.push(`/languages/${language}/${list.id}`)}
+          className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
+        >
+          <h2 className="text-xl font-semibold text-[#374151] mb-2">
+            {list.name}
+          </h2>
+        </button>
+      ))}
+    </div>
+  );
path: lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider enhancing accessibility with ARIA attributes.**

While the implementation is functional, consider adding ARIA attributes for better screen reader support, especially since these buttons act as navigation elements.


```diff
<button
  key={list.id}
  type="button"
  onClick={() => router.push(`/languages/${language}/${list.id}`)}
+  aria-label={`Go to ${list.name} question list`}
  className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
>
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  return (
    <div className="grid gap-4">
      {questionLists.map((list: QuestionList) => (
        <button
          key={list.id}
          type="button"
          onClick={() => router.push(`/languages/${language}/${list.id}`)}
          aria-label={`Go to ${list.name} question list`}
          className="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow text-left w-full"
        >
          <h2 className="text-xl font-semibold text-[#374151] mb-2">
            {list.name}
          </h2>
        </button>
      ))}
    </div>
  );
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 18-22: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits e46b341 to b5e12e3
created_at: 2025-04-10T11:04:05Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { BookOpen } from "lucide-react";
+import { useRouter } from "next/navigation";
+
+interface EmptyStateProps {
+  language: string;
+}
+
+export function EmptyState({ language }: EmptyStateProps) {
+  const router = useRouter();
+
+  return (
+    <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white flex items-center justify-center">
+      <div className="bg-white p-8 rounded-xl shadow-lg max-w-md w-full text-center">
+        <BookOpen className="h-12 w-12 text-[#2563eb] mx-auto mb-4" />
+        <h2 className="text-2xl font-bold text-[#374151] mb-2">
+          No Question Lists Available
+        </h2>
+        <p className="text-[#374151] mb-6">
+          {`We don't have any question lists for ${language} yet. Please check back later.`}
+        </p>
+        <button
+          onClick={() => router.push("/languages")}
+          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
+        >
+          Back to Languages
+        </button>
path: lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Add explicit button type for accessibility**

The button element should have an explicit type attribute for better accessibility.


```diff
<button
+  type="button"
  onClick={() => router.push("/languages")}
  className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
>
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        <button
          type="button"
          onClick={() => router.push("/languages")}
          className="bg-[#2563eb] text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
        >
          Back to Languages
        </button>
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 21-24: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits e46b341 to b5e12e3
created_at: 2025-04-10T11:04:05Z
author_association: NONE
diff_hunk: @@ -0,0 +1,51 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useAuth } from "@clerk/nextjs";
+import { useParams } from "next/navigation";
+import { fetchQuestionLists } from "@/utilities/api";
+import type { QuestionList } from "@/utilities/api-types";
+import { LoadingState } from "./LoadingState";
+import { ErrorState } from "./ErrorState";
+import { EmptyState } from "./EmptyState";
+import { QuestionListGrid } from "./QuestionListGrid";
+import { QuestionListHeader } from "./QuestionListHeader";
+
+export default function QuestionListComponent() {
+  const params = useParams();
+  const language = params.language as string;
+  const [questionLists, setQuestionLists] = useState<QuestionList[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(false);
+  const { getToken } = useAuth();
+
+  useEffect(() => {
+    const fetchLists = async () => {
+      try {
+        const lists = await fetchQuestionLists(language, getToken);
+        setQuestionLists(lists);
+        setError(false);
+      } catch (err) {
+        console.error("Error fetching question lists:", err);
+        setError(true);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchLists();
+  }, [language, getToken]);
path: lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Good implementation of data fetching logic**

The data fetching logic is well-implemented with proper error handling, state management, and dependency array specification. The try/catch with error logging and state updates follows best practices.



Consider using a data fetching library like React Query or SWR for additional features like caching, background updates, and automatic retries if this component's data fetching needs become more complex in the future.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-10T11:04:05Z
author_association: NONE

PR comments:
user: login: vercel[bot]
created_at: 2025-04-10T11:00:58Z
body: [vc]: #ouqwiWQ5HfwgZ+bXQfBGZJ4WB7qO6dlj9yp6s38syEA=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJsaW5nZXRpYyIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9hYmhpa3IyMTAwcy1wcm9qZWN0cy9saW5nZXRpYy9HQnMyVDFWRG52RnFEVHY4QkR4QWlGbUFDejF6IiwicHJldmlld1VybCI6ImxpbmdldGljLWdpdC0wNC0xMC1hZGRxdWVzdGlvbmxpc3RzLTkwYzUzNy1hYmhpa3IyMTAwcy1wcm9qZWN0cy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6ImxpbmdldGljLWdpdC0wNC0xMC1hZGRxdWVzdGlvbmxpc3RzLTkwYzUzNy1hYmhpa3IyMTAwcy1wcm9qZWN0cy52ZXJjZWwuYXBwIn0sInJvb3REaXJlY3RvcnkiOiJsaW5nZXRpYy1uZXh0anMtZnJvbnRlbmQifV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **lingetic** | ✅ Ready ([Inspect](https://vercel.com/abhikr2100s-projects/lingetic/GBs2T1VDnvFqDTv8BDxAiFmACz1z)) | [Visit Preview](https://lingetic-git-04-10-addquestionlists-90c537-abhikr2100s-projects.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/lingetic-git-04-10-addquestionlists-90c537-abhikr2100s-projects.vercel.app?via=pr-comment-feedback-link) | Apr 10, 2025 11:32am |


author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-10T11:01:10Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: rate limited by coderabbit.ai -->

> [!WARNING]
> ## Rate limit exceeded
> 
> @abhi-kr-2100 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait **2 minutes and 27 seconds** before requesting another review.
> 
> <details>
> <summary>⌛ How to resolve this issue?</summary>
> 
> After the wait time has elapsed, a review can be triggered using the `@coderabbitai review` command as a PR comment. Alternatively, push new commits to this PR.
> 
> We recommend that you space out your commits to avoid hitting the rate limit.
> 
> </details>
> 
> 
> <details>
> <summary>🚦 How do rate limits work?</summary>
> 
> CodeRabbit enforces hourly rate limits for each developer per organization.
> 
> Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.
> 
> Please see our [FAQ](https://docs.coderabbit.ai/faq) for further information.
> 
> </details>
> 
> <details>
> <summary>📥 Commits</summary>
> 
> Reviewing files that changed from the base of the PR and between b5e12e3299373d976d0340863d6504fe52f0e7fe and fd9f6e02c14b5f82c344ebd07d0f82af53acff60.
> 
> </details>
> 
> <details>
> <summary>📒 Files selected for processing (15)</summary>
> 
> * `lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx` (2 hunks)
> * `lingetic-nextjs-frontend/app/components/LanguagePlayCard.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/components/landing-page/LanguageCard.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/EmptyState.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/ErrorState.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/LoadingState.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/QuestionListComponent.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/QuestionListGrid.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/QuestionListHeader.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/LearnPageComponent.tsx` (2 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/useQuestions.ts` (3 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/page.tsx` (1 hunks)
> * `lingetic-nextjs-frontend/app/languages/[language]/useQuestionLists.ts` (1 hunks)
> * `lingetic-nextjs-frontend/utilities/api-types.ts` (1 hunks)
> * `lingetic-nextjs-frontend/utilities/api.ts` (3 hunks)
> 
> </details>

<!-- end of auto-generated comment: rate limited by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This pull request introduces changes to support a new `questionListId` parameter across several modules. Updates include modifications to the import paths and mock setups in tests, adjustments to link URL constructions in components, and the addition of several new React components for empty, error, and loading states, as well as components for displaying question lists. Backend API utilities are also updated to incorporate the new parameter into function calls and endpoints.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `lingetic-nextjs-frontend/__tests__/pages/learn/LearnPage.test.tsx` | Updated import path for `LearnPageComponent` and modified `useParams` mock to return both `language` and `questionListId`. |
| `lingetic-nextjs-frontend/app/components/{LanguagePlayCard.tsx, landing-page/LanguageCard.tsx}` | Removed the `/learn/` segment from the `href` attributes in Link components to update URL structure. |
| `lingetic-nextjs-frontend/app/languages/[language]/{EmptyState.tsx, ErrorState.tsx, LoadingState.tsx, QuestionListComponent.tsx, QuestionListGrid.tsx, QuestionListHeader.tsx, page.tsx}` | Added new UI components for displaying empty, error, and loading states; introduced components for question list display and a new `LanguagePage` that handles authentication-based rendering. |
| `lingetic-nextjs-frontend/app/languages/[language]/[questionListId]/{LearnPageComponent.tsx, useQuestions.ts}` | Updated components and hooks to extract and assert the presence of `questionListId`, and modified query keys and function signatures accordingly. |
| `lingetic-nextjs-frontend/utilities/{api-types.ts, api.ts}` | Introduced a new `QuestionList` interface, added a new `fetchQuestionLists` function, and updated existing API endpoints and functions to include `questionListId`. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
  participant U as User
  participant LP as LanguagePage
  participant QC as QuestionListComponent
  participant API as API Utilities

  U->>LP: Navigate to /languages/[language]
  alt User Signed In
    LP->>QC: Render QuestionListComponent
    QC->>API: fetchQuestionLists(language, token)
    API-->>QC: Return list of questions
    QC->>LP: Render header & grid with question lists
  else User Signed Out
    LP->>Redirect: Render RedirectToSignIn
  end
```

## Possibly related PRs

- **abhi-kr-2100/Lingetic#9**: Addresses handling of the `questionListId` in both the `LearnPageComponent` and `useQuestions` function.
- **abhi-kr-2100/Lingetic#20**: Modifies the `useQuestions` function to incorporate the `questionListId` parameter, aligning with this PR's changes.
- **abhi-kr-2100/Lingetic#119**: Focuses on updating the `LearnPageComponent` with the new `questionListId` parameter, similar to the modifications introduced here.

## Suggested labels

`Review effort 3/5`

## Poem

> I'm a bunny with code hops so spry,  
> Adding parameters to help us fly.  
> Question lists now bloom with new ID flair,  
> With links and components crafted with care.  
> Happy hops and ASCII cheers, coding without a care!  
> 🐰✨

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=abhi-kr-2100/Lingetic&utm_content=165):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: abhi-kr-2100
created_at: 2025-04-10T11:01:13Z
body: * **#165** <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/165?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈 <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/165?utm_source=stack-comment-view-in-graphite" target="_blank">(View in Graphite)</a>
* **#164** <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/164?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a>
* **#163** <a href="https://app.graphite.dev/github/pr/abhi-kr-2100/Lingetic/163?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a>
* `main`


<h2></h2>

This stack of pull requests is managed by <a href="https://graphite.dev?utm-source=stack-comment"><b>Graphite</b></a>. Learn more about <a href="https://stacking.dev/?utm_source=stack-comment">stacking</a>.
<!-- Current dependencies on/for this PR: -->
author_association: OWNER
user: login: gemini-code-assist[bot]
created_at: 2025-04-10T11:23:45Z
body: > [!WARNING]
> You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again!
author_association: NONE
user: login: gemini-code-assist[bot]
created_at: 2025-04-10T11:23:57Z
body: > [!WARNING]
> You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again!
author_association: NONE
user: login: gemini-code-assist[bot]
created_at: 2025-04-10T11:24:04Z
body: > [!WARNING]
> You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again!
author_association: NONE
user: login: gemini-code-assist[bot]
created_at: 2025-04-10T11:24:14Z
body: > [!WARNING]
> You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again!
author_association: NONE