|
|
@ -1,5 +1,6 @@ |
|
|
|
import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; |
|
|
|
import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; |
|
|
|
import CheckIcon from '../../icons/check.svg'; |
|
|
|
import CheckIcon from '../../icons/check.svg'; |
|
|
|
|
|
|
|
import ProgressIcon from '../../icons/progress.svg'; |
|
|
|
import CloseIcon from '../../icons/close.svg'; |
|
|
|
import CloseIcon from '../../icons/close.svg'; |
|
|
|
import ResetIcon from '../../icons/reset.svg'; |
|
|
|
import ResetIcon from '../../icons/reset.svg'; |
|
|
|
import SpinnerIcon from '../../icons/spinner.svg'; |
|
|
|
import SpinnerIcon from '../../icons/spinner.svg'; |
|
|
@ -11,10 +12,12 @@ import { useToggleTopic } from '../../hooks/use-toggle-topic'; |
|
|
|
import { httpGet } from '../../lib/http'; |
|
|
|
import { httpGet } from '../../lib/http'; |
|
|
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
import { |
|
|
|
import { |
|
|
|
|
|
|
|
getTopicStatus, |
|
|
|
isTopicDone, |
|
|
|
isTopicDone, |
|
|
|
renderTopicProgress, |
|
|
|
renderTopicProgress, |
|
|
|
|
|
|
|
ResourceProgressType, |
|
|
|
ResourceType, |
|
|
|
ResourceType, |
|
|
|
toggleMarkTopicDone as toggleMarkTopicDoneApi, |
|
|
|
updateResourceProgress as updateResourceProgressApi, |
|
|
|
} from '../../lib/resource-progress'; |
|
|
|
} from '../../lib/resource-progress'; |
|
|
|
import { pageLoadingMessage, sponsorHidden } from '../../stores/page'; |
|
|
|
import { pageLoadingMessage, sponsorHidden } from '../../stores/page'; |
|
|
|
|
|
|
|
|
|
|
@ -24,6 +27,7 @@ export function TopicDetail() { |
|
|
|
const [error, setError] = useState(''); |
|
|
|
const [error, setError] = useState(''); |
|
|
|
const [topicHtml, setTopicHtml] = useState(''); |
|
|
|
const [topicHtml, setTopicHtml] = useState(''); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [progress, setProgress] = useState<ResourceProgressType>('pending'); |
|
|
|
const [isDone, setIsDone] = useState<boolean>(); |
|
|
|
const [isDone, setIsDone] = useState<boolean>(); |
|
|
|
const [isUpdatingProgress, setIsUpdatingProgress] = useState(true); |
|
|
|
const [isUpdatingProgress, setIsUpdatingProgress] = useState(true); |
|
|
|
|
|
|
|
|
|
|
@ -49,13 +53,24 @@ export function TopicDetail() { |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const toggleMarkTopicDone = (isDone: boolean) => { |
|
|
|
const handleUpdateResourceProgress = (progress: ResourceProgressType) => { |
|
|
|
setIsUpdatingProgress(true); |
|
|
|
setIsUpdatingProgress(true); |
|
|
|
toggleMarkTopicDoneApi({ topicId, resourceId, resourceType }, isDone) |
|
|
|
updateResourceProgressApi( |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
topicId, |
|
|
|
|
|
|
|
resourceId, |
|
|
|
|
|
|
|
resourceType, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
progress |
|
|
|
|
|
|
|
) |
|
|
|
.then(() => { |
|
|
|
.then(() => { |
|
|
|
setIsDone(isDone); |
|
|
|
setProgress(progress); |
|
|
|
setIsActive(false); |
|
|
|
setIsActive(false); |
|
|
|
renderTopicProgress(topicId, isDone); |
|
|
|
renderTopicProgress( |
|
|
|
|
|
|
|
topicId, |
|
|
|
|
|
|
|
progress === 'done', |
|
|
|
|
|
|
|
progress === 'learning' |
|
|
|
|
|
|
|
); |
|
|
|
}) |
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
.catch((err) => { |
|
|
|
alert(err.message); |
|
|
|
alert(err.message); |
|
|
@ -73,10 +88,10 @@ export function TopicDetail() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setIsUpdatingProgress(true); |
|
|
|
setIsUpdatingProgress(true); |
|
|
|
isTopicDone({ topicId, resourceId, resourceType }) |
|
|
|
getTopicStatus({ topicId, resourceId, resourceType }) |
|
|
|
.then((status: boolean) => { |
|
|
|
.then((status) => { |
|
|
|
setIsUpdatingProgress(false); |
|
|
|
setIsUpdatingProgress(false); |
|
|
|
setIsDone(status); |
|
|
|
setProgress(status); |
|
|
|
}) |
|
|
|
}) |
|
|
|
.catch(console.error); |
|
|
|
.catch(console.error); |
|
|
|
}, [topicId, resourceId, resourceType]); |
|
|
|
}, [topicId, resourceId, resourceType]); |
|
|
@ -104,16 +119,19 @@ export function TopicDetail() { |
|
|
|
// Toggle the topic status
|
|
|
|
// Toggle the topic status
|
|
|
|
isTopicDone({ topicId, resourceId, resourceType }) |
|
|
|
isTopicDone({ topicId, resourceId, resourceType }) |
|
|
|
.then((oldIsDone) => { |
|
|
|
.then((oldIsDone) => { |
|
|
|
return toggleMarkTopicDoneApi( |
|
|
|
return updateResourceProgressApi( |
|
|
|
{ |
|
|
|
{ |
|
|
|
topicId, |
|
|
|
topicId, |
|
|
|
resourceId, |
|
|
|
resourceId, |
|
|
|
resourceType, |
|
|
|
resourceType, |
|
|
|
}, |
|
|
|
}, |
|
|
|
!oldIsDone |
|
|
|
oldIsDone ? 'pending' : 'done' |
|
|
|
); |
|
|
|
); |
|
|
|
}) |
|
|
|
}) |
|
|
|
.then((newIsDone) => renderTopicProgress(topicId, newIsDone)) |
|
|
|
.then((updatedResult) => { |
|
|
|
|
|
|
|
const newIsDone = updatedResult.done.includes(topicId); |
|
|
|
|
|
|
|
renderTopicProgress(topicId, newIsDone, false); |
|
|
|
|
|
|
|
}) |
|
|
|
.catch((err) => { |
|
|
|
.catch((err) => { |
|
|
|
alert(err.message); |
|
|
|
alert(err.message); |
|
|
|
console.error(err); |
|
|
|
console.error(err); |
|
|
@ -193,14 +211,24 @@ export function TopicDetail() { |
|
|
|
{/* Actions for the topic */} |
|
|
|
{/* Actions for the topic */} |
|
|
|
<div className="mb-2"> |
|
|
|
<div className="mb-2"> |
|
|
|
{isGuest && ( |
|
|
|
{isGuest && ( |
|
|
|
|
|
|
|
<div className="flex items-center gap-2"> |
|
|
|
<button |
|
|
|
<button |
|
|
|
data-popup="login-popup" |
|
|
|
data-popup="login-popup" |
|
|
|
className="inline-flex items-center rounded-md bg-green-600 p-1 px-2 text-sm text-white hover:bg-green-700" |
|
|
|
className="inline-flex items-center rounded-md bg-green-600 p-1 px-2 text-sm text-white hover:bg-green-700" |
|
|
|
onClick={() => setIsActive(false)} |
|
|
|
onClick={() => setIsActive(false)} |
|
|
|
> |
|
|
|
> |
|
|
|
<img alt="Check" class='w-3' src={CheckIcon} /> |
|
|
|
<img alt="Check" class="w-3" src={CheckIcon} /> |
|
|
|
<span className="ml-2">Mark as Done</span> |
|
|
|
<span className="ml-2">Mark as Done</span> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
|
|
|
|
<button |
|
|
|
|
|
|
|
data-popup="login-popup" |
|
|
|
|
|
|
|
class="inline-flex items-center rounded-md bg-gray-800 p-1 px-2 text-sm text-white hover:bg-black" |
|
|
|
|
|
|
|
onClick={() => setIsActive(false)} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<img alt="Learning" class="w-3" src={ProgressIcon} /> |
|
|
|
|
|
|
|
<span class="ml-2">In Progress</span> |
|
|
|
|
|
|
|
</button> |
|
|
|
|
|
|
|
</div> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{!isGuest && ( |
|
|
|
{!isGuest && ( |
|
|
@ -215,24 +243,53 @@ export function TopicDetail() { |
|
|
|
<span className="ml-2">Updating Status..</span> |
|
|
|
<span className="ml-2">Updating Status..</span> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
)} |
|
|
|
)} |
|
|
|
{!isUpdatingProgress && !isDone && ( |
|
|
|
{!isUpdatingProgress && progress === 'pending' && ( |
|
|
|
|
|
|
|
<div className="flex items-center gap-2"> |
|
|
|
<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={() => toggleMarkTopicDone(true)} |
|
|
|
onClick={() => handleUpdateResourceProgress('done')} |
|
|
|
> |
|
|
|
> |
|
|
|
<img alt="Check" class="w-3" src={CheckIcon} /> |
|
|
|
<img alt="Check" class="w-3" src={CheckIcon} /> |
|
|
|
<span className="ml-2">Mark as Done</span> |
|
|
|
<span className="ml-2">Mark as Done</span> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<button |
|
|
|
|
|
|
|
className="inline-flex items-center rounded-md border border-gray-800 bg-gray-800 p-1 px-2 text-sm text-white hover:bg-black" |
|
|
|
|
|
|
|
onClick={() => handleUpdateResourceProgress('learning')} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<img alt="Learning" class="w-3" src={ProgressIcon} /> |
|
|
|
|
|
|
|
<span className="ml-2">In Progress</span> |
|
|
|
|
|
|
|
</button> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{!isUpdatingProgress && progress === 'done' && ( |
|
|
|
|
|
|
|
<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" |
|
|
|
|
|
|
|
onClick={() => handleUpdateResourceProgress('pending')} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<img alt="Check" class="h-4" src={ResetIcon} /> |
|
|
|
|
|
|
|
<span className="ml-2">Mark as Pending</span> |
|
|
|
|
|
|
|
</button> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{!isUpdatingProgress && isDone && ( |
|
|
|
{!isUpdatingProgress && progress === 'learning' && ( |
|
|
|
|
|
|
|
<div className="flex items-center gap-2"> |
|
|
|
|
|
|
|
<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" |
|
|
|
|
|
|
|
onClick={() => handleUpdateResourceProgress('done')} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<img alt="Check" class="w-3" src={CheckIcon} /> |
|
|
|
|
|
|
|
<span className="ml-2">Mark as Done</span> |
|
|
|
|
|
|
|
</button> |
|
|
|
<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={() => toggleMarkTopicDone(false)} |
|
|
|
onClick={() => handleUpdateResourceProgress('pending')} |
|
|
|
> |
|
|
|
> |
|
|
|
<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> |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
|
|
|
|
</div> |
|
|
|
)} |
|
|
|
)} |
|
|
|
</> |
|
|
|
</> |
|
|
|
)} |
|
|
|
)} |
|
|
|