Update topic done functionality

pull/3813/head
Kamran Ahmed 2 years ago
parent 78e4c38c97
commit 20db0baec5
  1. 18
      src/components/TopicDetail/TopicDetail.tsx
  2. 62
      src/lib/resource-progress.ts

@ -10,9 +10,10 @@ import { httpGet } from '../../lib/http';
import { isLoggedIn } from '../../lib/jwt'; import { isLoggedIn } from '../../lib/jwt';
import { import {
isTopicDone, isTopicDone,
renderTopicProgress,
ResourceType, ResourceType,
toggleMarkTopicDone, toggleMarkTopicDone as toggleMarkTopicDoneApi,
} from '../../lib/user-resource-progress'; } from '../../lib/resource-progress';
import { useKeydown } from '../../hooks/use-keydown'; import { useKeydown } from '../../hooks/use-keydown';
export function TopicDetail() { export function TopicDetail() {
@ -32,22 +33,21 @@ export function TopicDetail() {
const [resourceId, setResourceId] = useState(''); const [resourceId, setResourceId] = useState('');
const [resourceType, setResourceType] = useState<ResourceType>('roadmap'); const [resourceType, setResourceType] = useState<ResourceType>('roadmap');
const toggleResourceProgress = (isDone: boolean) => { const toggleMarkTopicDone = (isDone: boolean) => {
setIsUpdatingProgress(true); setIsUpdatingProgress(true);
toggleMarkTopicDone({ topicId, resourceId, resourceType }, isDone) toggleMarkTopicDoneApi({ topicId, resourceId, resourceType }, isDone)
.then(() => { .then(() => {
setIsDone(isDone); setIsDone(isDone);
setIsActive(false); setIsActive(false);
renderTopicProgress(topicId, isDone);
}) })
.catch(err => { .catch((err) => {
alert(err.message); alert(err.message);
console.error(err); console.error(err);
}) })
.finally(() => { .finally(() => {
setIsUpdatingProgress(false); setIsUpdatingProgress(false);
}); });
console.log('toggle', isDone);
}; };
// Load the topic status when the topic detail is active // Load the topic status when the topic detail is active
@ -168,7 +168,7 @@ export function TopicDetail() {
{!isUpdatingProgress && !isDone && ( {!isUpdatingProgress && !isDone && (
<button <button
className="inline-flex items-center rounded-md border border-green-600 bg-green-600 p-1 px-2 text-sm text-white hover:bg-green-700" className="inline-flex items-center rounded-md border border-green-600 bg-green-600 p-1 px-2 text-sm text-white hover:bg-green-700"
onClick={() => toggleResourceProgress(true)} onClick={() => toggleMarkTopicDone(true)}
> >
<img alt="Check" class="h-4 w-4" src={CheckIcon} /> <img alt="Check" class="h-4 w-4" src={CheckIcon} />
<span className="ml-2">Mark as Done</span> <span className="ml-2">Mark as Done</span>
@ -178,7 +178,7 @@ export function TopicDetail() {
{!isUpdatingProgress && isDone && ( {!isUpdatingProgress && isDone && (
<button <button
className="inline-flex items-center rounded-md border border-red-600 bg-red-600 p-1 px-2 text-sm text-white hover:bg-red-700" className="inline-flex items-center rounded-md border border-red-600 bg-red-600 p-1 px-2 text-sm text-white hover:bg-red-700"
onClick={() => toggleResourceProgress(false)} onClick={() => toggleMarkTopicDone(false)}
> >
<img alt="Check" class="h-4" src={ResetIcon} /> <img alt="Check" class="h-4" src={ResetIcon} />
<span className="ml-2">Mark as Pending</span> <span className="ml-2">Mark as Pending</span>

@ -1,6 +1,7 @@
import { httpGet, httpPatch } from './http'; import { httpGet, httpPatch } from './http';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { TOKEN_COOKIE_NAME } from './jwt'; import { TOKEN_COOKIE_NAME } from './jwt';
import Element = astroHTML.JSX.Element;
export type ResourceType = 'roadmap' | 'best-practice'; export type ResourceType = 'roadmap' | 'best-practice';
@ -12,7 +13,7 @@ type TopicMeta = {
export async function isTopicDone(topic: TopicMeta): Promise<boolean> { export async function isTopicDone(topic: TopicMeta): Promise<boolean> {
const { topicId, resourceType, resourceId } = topic; const { topicId, resourceType, resourceId } = topic;
const doneItems = await getUserResourceProgress(resourceType, resourceId); const doneItems = await getResourceProgress(resourceType, resourceId);
if (!doneItems) { if (!doneItems) {
return false; return false;
@ -41,9 +42,10 @@ export async function toggleMarkTopicDone(
throw new Error(error?.message || 'Something went wrong'); throw new Error(error?.message || 'Something went wrong');
} }
setUserResourceProgress(resourceType, resourceId, response.done); setResourceProgress(resourceType, resourceId, response.done);
} }
export async function getUserResourceProgress(
export async function getResourceProgress(
resourceType: 'roadmap' | 'best-practice', resourceType: 'roadmap' | 'best-practice',
resourceId: string resourceId: string
): Promise<string[]> { ): Promise<string[]> {
@ -92,12 +94,12 @@ async function loadFreshProgress(
return []; return [];
} }
setUserResourceProgress(resourceType, resourceId, response.done); setResourceProgress(resourceType, resourceId, response.done);
return response.done; return response.done;
} }
export function setUserResourceProgress( export function setResourceProgress(
resourceType: 'roadmap' | 'best-practice', resourceType: 'roadmap' | 'best-practice',
resourceId: string, resourceId: string,
done: string[] done: string[]
@ -110,3 +112,53 @@ export function setUserResourceProgress(
}) })
); );
} }
export function renderTopicProgress(topicId: string, isDone: boolean) {
const matchingElements: Element[] = [];
// Elements having sort order in the beginning of the group id
document
.querySelectorAll(`[data-group-id$="-${topicId}"]`)
.forEach((element: unknown) => {
const foundGroupId =
(element as HTMLOrSVGElement)?.dataset?.groupId || '';
const validGroupRegex = new RegExp(`^\\d+-${topicId}$`);
if (validGroupRegex.test(foundGroupId)) {
matchingElements.push(element);
}
});
// Elements with exact match of the topic id
document
.querySelectorAll(`[data-group-id="${topicId}"]`)
.forEach((element) => {
matchingElements.push(element);
});
// Matching "check:XXXX" box of the topic
document
.querySelectorAll(`[data-group-id="check:${topicId}"]`)
.forEach((element) => {
matchingElements.push(element);
});
matchingElements.forEach((element) => {
if (isDone) {
element.classList.add('done');
} else {
element.classList.remove('done');
}
});
}
export async function renderResourceProgress(
resourceType: ResourceType,
resourceId: string
) {
const progress = await getResourceProgress(resourceType, resourceId);
progress.forEach((topicId) => {
renderTopicProgress(topicId, true);
});
}
Loading…
Cancel
Save