Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Pull Request

## Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.

Fixes # (issue)

## Type of change

Please select all relevant options, then delete those which are irrelevant.

- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Page content update.

## Validation

Please describe how you validate your proposed changes. Provide instructions so we can reproduce this result.

- [ ] Test A

## Checklist

- [ ] My code follows proposed/requested changes to the related issues.
- [ ] The [coding guidelines](https://github.com/S7-OpenLearning-Individual/DesignPatternPedia?tab=readme-ov-file#coding-standards) have been applied correctly and thoroughly.
- [ ] `npm run lint:mdx` passes without errors.
- [ ] I have performed a self-review of my own code and corrected any misspellings or grammatical errors.
- [ ] I have tested the changes locally and ensured there are no errors or functional problems.

## Screenshots (if applicable)

Please add screenshots to demonstrate the changes made (if applicable).
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ This website is built using [Docusaurus](https://docusaurus.io/), a modern stati
2. All images have `alt` texts explaining their purpose and contents.
3. All basic page elements that can be re-used should be turned into components.
4. Code is written in American English.
5. Page content is written in Queens English.
5. Page content is written in Queen's English.
6. Page content is cited, sourced, and referenced where deemed necessary.
7. All docs/pages are `.mdx` files.
8. Code compiles and tests pass.
9. Directories follow the correct pattern structure.
10. Each page is built using the [template](/template.mdx) (validated by `npm run lint:mdx`).
10. Each _pattern_ page is built using the [template](/template.mdx) (validated by `npm run lint:mdx`).
11. Custom components should not implement their own title, they should use the correct heading (#) level in the page itself to ensure proper url based linking.
12. Images need to have padding applied around them, optimally `2rem`.
13. Code has no 'TODO' blocks, only a 'FUTURE_WORK' block may be present with a reference to an issue or task.
13. Source code contains no 'TODO' blocks, only a 'FUTURE_WORK' block may be present with a reference to an issue or task.

## Installation

Expand Down
5 changes: 4 additions & 1 deletion src/components/navigator/AnsweredQuestion.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import QuestionCard, { YesOrNo } from "./QuestionCard";
import QuestionCard from "./QuestionCard";
import styles from "./navigator.module.css";
import { YesOrNo } from "@site/src/models/yes-or-no";

interface AnsweredQuestionProps {
question: string;
Expand All @@ -22,11 +23,13 @@ const AnsweredQuestion: React.FC<AnsweredQuestionProps> = ({
question={question}
selectedAnswer={answer}
onAnswerYes={() => {
//Only call if the answer changed
if (answer !== "yes") {
onChangeAnswer("yes");
}
}}
onAnswerNo={() => {
//Only call if the answer changed
Comment on lines +26 to +32
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should have a space after the double slashes for better readability. Change "//Only" to "// Only".

Suggested change
//Only call if the answer changed
if (answer !== "yes") {
onChangeAnswer("yes");
}
}}
onAnswerNo={() => {
//Only call if the answer changed
// Only call if the answer changed
if (answer !== "yes") {
onChangeAnswer("yes");
}
}}
onAnswerNo={() => {
// Only call if the answer changed

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +32
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should have a space after the double slashes for better readability. Change "//Only" to "// Only".

Suggested change
//Only call if the answer changed
if (answer !== "yes") {
onChangeAnswer("yes");
}
}}
onAnswerNo={() => {
//Only call if the answer changed
// Only call if the answer changed
if (answer !== "yes") {
onChangeAnswer("yes");
}
}}
onAnswerNo={() => {
// Only call if the answer changed

Copilot uses AI. Check for mistakes.
if (answer !== "no") {
onChangeAnswer("no");
}
Expand Down
29 changes: 14 additions & 15 deletions src/components/navigator/NavigatorContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import React, { useState } from "react";
import {
decisionTree,
getNode,
getNextNode,
isPatternNode,
} from "@site/src/data/decision-tree";
import QuestionCard from "./QuestionCard";
import PatternResult from "./PatternResult";
import AnsweredQuestion from "./AnsweredQuestion";
import styles from "./navigator.module.css";

export interface Answer {
nodeId: string;
answer: "yes" | "no";
}
import {
getNextNode,
getNode,
isPatternNode,
} from "@site/src/utils/decision-tree-helper";
import { YesOrNo } from "@site/src/models/yes-or-no";
import { Answer } from "@site/src/models/answer";

const NavigatorContainer: React.FC = () => {
const [answers, setAnswers] = useState<Answer[]>([]);
Expand All @@ -30,11 +26,11 @@ const NavigatorContainer: React.FC = () => {
return <div>Error: Node not found</div>;
}

const handleAnswer = (answer: "yes" | "no") => {
const handleAnswer = (answer: YesOrNo) => {
setAnswers([...answers, { nodeId: currentNodeId, answer }]);
};

const handleGoBack = (index: number, newAnswer?: "yes" | "no") => {
const handleGoBack = (index: number, newAnswer?: YesOrNo) => {
const targetAnswer = newAnswer || answers[index].answer;
setAnswers(
answers
Expand All @@ -54,7 +50,10 @@ const NavigatorContainer: React.FC = () => {
{/* Show all previous questions with their selected answers */}
{answers.map((answer, index) => {
const node = getNode(answer.nodeId);
if (!node) return null;

if (!node) {
return null;
}

// Check if the next node after this answer is a pattern (not a question)
const nextNodeId = getNextNode(answer.nodeId, answer.answer);
Expand All @@ -65,7 +64,7 @@ const NavigatorContainer: React.FC = () => {
return (
<AnsweredQuestion
key={index}
question={node.question || ""}
question={node.question}
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question property is optional in the DecisionNode interface (can be undefined), but here it's passed directly without a fallback. This creates an inconsistency with line 85 where the same property is safely handled with "|| ''". For type safety and consistency, this should also use a fallback.

Suggested change
question={node.question}
question={node.question || ""}

Copilot uses AI. Check for mistakes.
answer={answer.answer}
onChangeAnswer={(newAnswer) => handleGoBack(index, newAnswer)}
showDivider={!isNextNodePattern}
Expand Down
2 changes: 0 additions & 2 deletions src/components/navigator/PatternResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import React from "react";
import styles from "./navigator.module.css";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";

const baseURL = "/DesignPatternPedia/docs";

interface PatternResultProps {
name: string;
description: string;
Expand Down
3 changes: 1 addition & 2 deletions src/components/navigator/QuestionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import styles from "./navigator.module.css";

export type YesOrNo = "yes" | "no";
import { YesOrNo } from "@site/src/models/yes-or-no";

interface QuestionCardProps {
question: string;
Expand Down
6 changes: 1 addition & 5 deletions src/components/navigator/navigator.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,6 @@
}

.answerBtn {
min-width: 100%;
}

.answerButtons {
flex-direction: column;
min-width: 30vw;
}
}
53 changes: 2 additions & 51 deletions src/data/decision-tree.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
// Decision Tree Node Types
export type NodeType = "question" | "pattern";

export interface DecisionNode {
id: string;
type: NodeType;
question?: string; // For question nodes
title?: string; // For pattern nodes
description?: string; // For pattern nodes
icon?: string; // Optional icon identifier
yesPath?: string; // ID of next node if "Yes"
noPath?: string; // ID of next node if "No"
pattern?: {
name: string;
description: string;
path: string;
};
}

export interface DecisionTree {
[nodeId: string]: DecisionNode;
}

// Decision Tree Structure
import { DecisionTree } from "../models/decision-tree";

export const decisionTree: DecisionTree = {
// First main decision
q1: {
Expand Down Expand Up @@ -428,30 +406,3 @@ export const decisionTree: DecisionTree = {
},
},
};

// Helper function to get node by ID
export const getNode = (nodeId: string): DecisionNode | undefined => {
return decisionTree[nodeId];
};

// Helper function to get next node based on answer
export const getNextNode = (
nodeId: string,
answer: "yes" | "no"
): string | undefined => {
const node = getNode(nodeId);
if (!node) return undefined;
return answer === "yes" ? node.yesPath : node.noPath;
};

// Helper function to check if node is a pattern endpoint
export const isPatternNode = (nodeId: string): boolean => {
const node = getNode(nodeId);
return node?.type === "pattern";
};

// Helper function to check if node is a question
export const isQuestionNode = (nodeId: string): boolean => {
const node = getNode(nodeId);
return node?.type === "question";
};
6 changes: 6 additions & 0 deletions src/models/answer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { YesOrNo } from "./yes-or-no";

export interface Answer {
nodeId: string;
answer: YesOrNo;
}
17 changes: 17 additions & 0 deletions src/models/decision-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NodeType } from "./node-type";

export interface DecisionNode {
id: string;
type: NodeType;
question?: string;
title?: string;
description?: string;
icon?: string;
yesPath?: string;
noPath?: string;
pattern?: {
name: string;
description: string;
path: string;
};
}
5 changes: 5 additions & 0 deletions src/models/decision-tree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { DecisionNode } from "./decision-node";

export interface DecisionTree {
[nodeId: string]: DecisionNode;
}
1 change: 1 addition & 0 deletions src/models/node-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type NodeType = "question" | "pattern";
1 change: 1 addition & 0 deletions src/models/yes-or-no.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type YesOrNo = "yes" | "no";
36 changes: 36 additions & 0 deletions src/utils/decision-tree-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { YesOrNo } from "../components/navigator/QuestionCard";
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import path is incorrect. YesOrNo has been moved to the models directory and should be imported from "@site/src/models/yes-or-no" instead of from QuestionCard.

Suggested change
import { YesOrNo } from "../components/navigator/QuestionCard";
import { YesOrNo } from "@site/src/models/yes-or-no";

Copilot uses AI. Check for mistakes.
import { DecisionNode, decisionTree } from "../data/decision-tree";
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import path is incorrect. DecisionNode has been moved to the models directory and should be imported from "@site/src/models/decision-node" instead of from the data/decision-tree file which no longer exports it.

Suggested change
import { DecisionNode, decisionTree } from "../data/decision-tree";
import { DecisionNode } from "@site/src/models/decision-node";
import { decisionTree } from "../data/decision-tree";

Copilot uses AI. Check for mistakes.

// Helper function to get node by ID
export const getNode = (nodeId: string): DecisionNode | undefined => {
return decisionTree[nodeId];
};

// Helper function to get next node based on answer
export const getNextNode = (
nodeId: string,
answer: YesOrNo
): string | undefined => {
const node = getNode(nodeId);
if (!node) {
return undefined;
}

if (answer === "yes") {
return node.yesPath;
}

return node.noPath;
};

// Helper function to check if node is a pattern endpoint
export const isPatternNode = (nodeId: string): boolean => {
const node = getNode(nodeId);
return node?.type === "pattern";
};

// Helper function to check if node is a question
export const isQuestionNode = (nodeId: string): boolean => {
const node = getNode(nodeId);
return node?.type === "question";
};