Skip to content

Commit

Permalink
Merge pull request #143 from kamranahmedse/develop
Browse files Browse the repository at this point in the history
Create a new pull request by comparing changes across two branches
  • Loading branch information
GulajavaMinistudio authored Jun 4, 2024
2 parents 49ffb64 + 5648b14 commit 1664c47
Show file tree
Hide file tree
Showing 32 changed files with 3,321 additions and 3,196 deletions.
36 changes: 10 additions & 26 deletions src/components/Questions/QuestionFinished.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,19 @@ type ProgressStatButtonProps = {
icon: ReactNode;
label: string;
count: number;
onClick: () => void;
};

function ProgressStatButton(props: ProgressStatButtonProps) {
const { icon, label, count, onClick, isDisabled = false } = props;
function ProgressStatLabel(props: ProgressStatButtonProps) {
const { icon, label, count } = props;

return (
<button
disabled={isDisabled}
onClick={onClick}
className="group relative flex flex-1 items-center overflow-hidden rounded-md border border-gray-300 bg-white px-2 py-2 text-sm text-black transition-colors hover:border-black disabled:pointer-events-none disabled:opacity-50 sm:rounded-xl sm:px-4 sm:py-3 sm:text-base"
>
<span className="group relative flex flex-1 items-center overflow-hidden rounded-md border border-gray-300 bg-white px-2 py-2 text-sm text-black transition-colors disabled:opacity-50 sm:rounded-xl sm:px-4 sm:py-3 sm:text-base">
{icon}
<span className="flex flex-grow justify-between">
<span>{label}</span>
<span>{count}</span>
</span>

<span className="absolute left-0 right-0 top-full flex h-full items-center justify-center border border-black bg-black text-white transition-all duration-200 group-hover:top-0">
Restart Asking
</span>
</button>
</span>
);
}

Expand All @@ -43,12 +34,11 @@ type QuestionFinishedProps = {
didNotKnowCount: number;
skippedCount: number;
totalCount: number;
onReset: (type: QuestionProgressType | 'reset') => void;
onReset: () => void;
};

export function QuestionFinished(props: QuestionFinishedProps) {
const { knowCount, didNotKnowCount, skippedCount, totalCount, onReset } =
props;
const { knowCount, didNotKnowCount, skippedCount, onReset } = props;

return (
<div className="relative flex flex-grow flex-col items-center justify-center px-4 sm:px-0">
Expand All @@ -63,31 +53,25 @@ export function QuestionFinished(props: QuestionFinishedProps) {
</p>

<div className="mb-5 mt-5 flex w-full flex-col gap-1.5 px-2 sm:flex-row sm:gap-3 sm:px-16">
<ProgressStatButton
<ProgressStatLabel
icon={<ThumbsUp className="mr-1 h-4" />}
label="Knew"
count={knowCount}
isDisabled={knowCount === 0}
onClick={() => onReset('know')}
/>
<ProgressStatButton
<ProgressStatLabel
icon={<Sparkles className="mr-1 h-4" />}
label="Learned"
count={didNotKnowCount}
isDisabled={didNotKnowCount === 0}
onClick={() => onReset('dontKnow')}
/>
<ProgressStatButton
<ProgressStatLabel
icon={<SkipForward className="mr-1 h-4" />}
label="Skipped"
count={skippedCount}
isDisabled={skippedCount === 0}
onClick={() => onReset('skip')}
/>
</div>
<div className="mb-4 mt-2 text-sm sm:mb-0">
<button
onClick={() => onReset('reset')}
onClick={() => onReset()}
className="flex items-center gap-0.5 text-sm text-red-700 hover:text-black sm:text-base"
>
<RefreshCcw className="mr-1 h-4" />
Expand Down
99 changes: 53 additions & 46 deletions src/components/Questions/QuestionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ type QuestionsListProps = {
};

export function QuestionsList(props: QuestionsListProps) {
const { questions: unshuffledQuestions, groupId } = props;
const { questions: defaultQuestions, groupId } = props;

const toast = useToast();

const [questions, setQuestions] = useState(defaultQuestions);
const [isLoading, setIsLoading] = useState(true);
const [showConfetti, setShowConfetti] = useState(false);
const [questions, setQuestions] = useState<QuestionType[]>();
const [pendingQuestions, setPendingQuestions] = useState<QuestionType[]>([]);
const [currQuestionIndex, setCurrQuestionIndex] = useState(0);

const [userProgress, setUserProgress] = useState<UserQuestionProgress>();
const containerRef = useRef<HTMLDivElement>(null);
Expand All @@ -57,47 +57,37 @@ export function QuestionsList(props: QuestionsListProps) {
return response;
}

async function loadQuestions() {
async function prepareProgress() {
const userProgress = await fetchUserProgress();
setUserProgress(userProgress);

const knownQuestions = userProgress?.know || [];
const didNotKnowQuestions = userProgress?.dontKnow || [];
const skipQuestions = userProgress?.skip || [];

const pendingQuestions = unshuffledQuestions.filter((question) => {
const pendingQuestionIndex = questions.findIndex((question) => {
return (
!knownQuestions.includes(question.id) &&
!didNotKnowQuestions.includes(question.id) &&
!skipQuestions.includes(question.id)
);
});

// Shuffle and set pending questions
// setPendingQuestions(pendingQuestions.sort(() => Math.random() - 0.5));
setPendingQuestions(pendingQuestions);
setQuestions(unshuffledQuestions);

setCurrQuestionIndex(pendingQuestionIndex);
setIsLoading(false);
}

async function resetProgress(type: QuestionProgressType | 'reset' = 'reset') {
async function resetProgress() {
let knownQuestions = userProgress?.know || [];
let didNotKnowQuestions = userProgress?.dontKnow || [];
let skipQuestions = userProgress?.skip || [];

if (!isLoggedIn()) {
if (type === 'know') {
knownQuestions = [];
} else if (type === 'dontKnow') {
didNotKnowQuestions = [];
} else if (type === 'skip') {
skipQuestions = [];
} else if (type === 'reset') {
knownQuestions = [];
didNotKnowQuestions = [];
skipQuestions = [];
}
setQuestions(defaultQuestions);

knownQuestions = [];
didNotKnowQuestions = [];
skipQuestions = [];
} else {
setIsLoading(true);

Expand All @@ -106,7 +96,7 @@ export function QuestionsList(props: QuestionsListProps) {
import.meta.env.PUBLIC_API_URL
}/v1-reset-question-progress/${groupId}`,
{
status: type,
status: 'reset',
},
);

Expand All @@ -120,21 +110,13 @@ export function QuestionsList(props: QuestionsListProps) {
skipQuestions = response?.skip || [];
}

const pendingQuestions = unshuffledQuestions.filter((question) => {
return (
!knownQuestions.includes(question.id) &&
!didNotKnowQuestions.includes(question.id) &&
!skipQuestions.includes(question.id)
);
});

setCurrQuestionIndex(0);
setUserProgress({
know: knownQuestions,
dontKnow: didNotKnowQuestions,
skip: skipQuestions,
});

setPendingQuestions(pendingQuestions.sort(() => Math.random() - 0.5));
setIsLoading(false);
}

Expand Down Expand Up @@ -173,42 +155,67 @@ export function QuestionsList(props: QuestionsListProps) {
newProgress = response;
}

const updatedQuestionList = pendingQuestions.filter(
(q) => q.id !== questionId,
);
const nextQuestionIndex = currQuestionIndex + 1;

setUserProgress(newProgress);
setPendingQuestions(updatedQuestionList);
setIsLoading(false);

if (updatedQuestionList.length === 0) {
if (!nextQuestionIndex || !questions[nextQuestionIndex]) {
setShowConfetti(true);
}

setCurrQuestionIndex(nextQuestionIndex);
}

useEffect(() => {
loadQuestions().then(() => null);
}, [unshuffledQuestions]);
prepareProgress().then(() => null);
}, [questions]);

const knowCount = userProgress?.know.length || 0;
const dontKnowCount = userProgress?.dontKnow.length || 0;
const skipCount = userProgress?.skip.length || 0;
const hasProgress = knowCount > 0 || dontKnowCount > 0 || skipCount > 0;

const currQuestion = pendingQuestions[0];
const hasFinished = !isLoading && hasProgress && !currQuestion;
const currQuestion = questions[currQuestionIndex];
const hasFinished = !isLoading && hasProgress && currQuestionIndex === -1;

return (
<div className="mb-0 gap-3 text-center sm:mb-40">
<QuestionsProgress
knowCount={knowCount}
didNotKnowCount={dontKnowCount}
skippedCount={skipCount}
totalCount={unshuffledQuestions?.length || questions?.length}
totalCount={questions?.length}
isLoading={isLoading}
showLoginAlert={!isLoggedIn() && hasProgress}
onResetClick={() => {
resetProgress('reset').finally(() => null);
resetProgress().finally(() => null);
}}
onNextClick={() => {
if (
currQuestionIndex !== -1 &&
currQuestionIndex < questions.length - 1
) {
updateQuestionStatus('skip', currQuestion.id).finally(() => null);
}
}}
onPrevClick={() => {
if (currQuestionIndex > 0) {
const prevQuestion = questions[currQuestionIndex - 1];
// remove last question from the progress of the user
const tempUserProgress = {
know:
userProgress?.know.filter((id) => id !== prevQuestion.id) || [],
dontKnow:
userProgress?.dontKnow.filter((id) => id !== prevQuestion.id) ||
[],
skip:
userProgress?.skip.filter((id) => id !== prevQuestion.id) || [],
};

setUserProgress(tempUserProgress);
setCurrQuestionIndex(currQuestionIndex - 1);
}
}}
/>

Expand All @@ -228,12 +235,12 @@ export function QuestionsList(props: QuestionsListProps) {
>
{hasFinished && (
<QuestionFinished
totalCount={unshuffledQuestions?.length || questions?.length || 0}
totalCount={questions?.length || 0}
knowCount={knowCount}
didNotKnowCount={dontKnowCount}
skippedCount={skipCount}
onReset={(type: QuestionProgressType | 'reset') => {
resetProgress(type).finally(() => null);
onReset={() => {
resetProgress().finally(() => null);
}}
/>
)}
Expand Down
40 changes: 31 additions & 9 deletions src/components/Questions/QuestionsProgress.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { CheckCircle, RotateCcw, SkipForward, Sparkles } from 'lucide-react';
import {
CheckCircle,
ChevronLeft,
ChevronRight,
RotateCcw,
SkipForward,
Sparkles,
} from 'lucide-react';
import { showLoginPopup } from '../../lib/popup';

type QuestionsProgressProps = {
Expand All @@ -9,6 +16,8 @@ type QuestionsProgressProps = {
totalCount?: number;
skippedCount?: number;
onResetClick?: () => void;
onPrevClick?: () => void;
onNextClick?: () => void;
};

export function QuestionsProgress(props: QuestionsProgressProps) {
Expand All @@ -20,6 +29,8 @@ export function QuestionsProgress(props: QuestionsProgressProps) {
totalCount = 0,
skippedCount = 0,
onResetClick = () => null,
onPrevClick = () => null,
onNextClick = () => null,
} = props;

const totalSolved = knowCount + didNotKnowCount + skippedCount;
Expand All @@ -36,8 +47,22 @@ export function QuestionsProgress(props: QuestionsProgressProps) {
}}
/>
</div>
<span className="ml-3 text-sm">
{totalSolved} / {totalCount}
<span className="ml-3 flex items-center text-sm">
<button
onClick={onPrevClick}
className="text-zinc-400 hover:text-black"
>
<ChevronLeft className="h-4" strokeWidth={3} />
</button>
<span className="block min-w-[41px] text-center">
<span className="tabular-nums">{totalSolved}</span> / {totalCount}
</span>
<button
onClick={onNextClick}
className="text-zinc-400 hover:text-black"
>
<ChevronRight className="h-4" strokeWidth={3} />
</button>
</span>
</div>

Expand All @@ -46,26 +71,23 @@ export function QuestionsProgress(props: QuestionsProgressProps) {
<CheckCircle className="mr-1 h-4" />
<span>Knew</span>
<span className="ml-2 rounded-md bg-gray-200/80 px-1.5 font-medium text-black">
<span className="tabular-nums">{knowCount}</span>{' '}
Items
<span className="tabular-nums">{knowCount}</span> Items
</span>
</span>

<span className="flex items-center">
<Sparkles className="mr-1 h-4" />
<span>Learnt</span>
<span className="ml-2 rounded-md bg-gray-200/80 px-1.5 font-medium text-black">
<span className="tabular-nums">{didNotKnowCount}</span>{' '}
Items
<span className="tabular-nums">{didNotKnowCount}</span> Items
</span>
</span>

<span className="flex items-center">
<SkipForward className="mr-1 h-4" />
<span>Skipped</span>
<span className="ml-2 rounded-md bg-gray-200/80 px-1.5 font-medium text-black">
<span className="tabular-nums">{skippedCount}</span>{' '}
Items
<span className="tabular-nums">{skippedCount}</span> Items
</span>
</span>

Expand Down
4 changes: 2 additions & 2 deletions src/data/question-groups/backend/content/ci-cd.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
There are multiple considerations to have while setting up Continuous Integration and Continuous Delivery pipelines:

- **Using source control** as the trigger for the entire process (git for example). The build pipelines for your backend services should get executed when you push your code into a specific branch.
- **Pick the right CI/CD** platform for your needs, there are many out there such as GitHub, Gitlab CI, CircleCI and more.
- **Pick the right CI/CD** platform for your needs, there are many out there such as GitHub Actions, GitLab CI/CD, CircleCI and more.
- Make sure you have **automated unit tests** that can be executed inside these pipelines.
- **Automatic deployment** should happen only if all tests are executed successfully, otherwise, the pipeline should fail, preventing broken code from reaching any environment.
- **Use an artifact repository** such as JFrog Artifactory or Nexus Repository to store successfully built services.
- Finally, consider setting up a **rollback strategy** in case something goes wrong and the final deployed version of your service is corrupted somehow.
- Finally, consider setting up a **rollback strategy** in case something goes wrong and the final deployed version of your service is corrupted somehow.
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Well Architected Framework

AWS Well-Architected Framework is a set of strategic guidelines provided by Amazon Web Services. It is designed to provide high-performing and resilient systems while maintaining cost efficiency. The framework divides the architectural best practices across five pillars which include operational excellence, security, reliability, performance efficiency, and cost optimization. With this framework, you can assess and improve your cloud-based architectures and applications by leveraging AWS technologies.
AWS Well-Architected Framework is a set of strategic guidelines provided by Amazon Web Services. It is designed to provide high-performing and resilient systems while maintaining cost efficiency. The framework divides the architectural best practices across six pillars which include operational excellence, security, reliability, performance efficiency, cost optimization and the sustainability. With this framework, you can assess and improve your cloud-based architectures and applications by leveraging AWS technologies.

Visit the following resources to learn more:

- [AWS Well-Architected](https://aws.amazon.com/architecture/well-architected)
Loading

0 comments on commit 1664c47

Please sign in to comment.