1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-01 21:32:35 +02:00
This commit is contained in:
Arik Chakma
2025-07-05 01:42:58 +06:00
parent 0bb701ee13
commit 7a07d02402
4 changed files with 105 additions and 29 deletions

View File

@@ -1,12 +1,17 @@
import { PersonStandingIcon } from 'lucide-react';
import { Loader2Icon, PersonStandingIcon } from 'lucide-react';
import { useState } from 'react';
import { usePersonalizedRoadmap } from '../../hooks/use-personalized-roadmap';
import { renderTopicProgress } from '../../lib/resource-progress';
import {
loadFreshProgress,
renderTopicProgress,
} from '../../lib/resource-progress';
import { PersonalizedRoadmapModal } from './PersonalizedRoadmapModal';
import { useMutation } from '@tanstack/react-query';
import { useMutation, useQuery } from '@tanstack/react-query';
import { httpPost } from '../../lib/query-http';
import { useToast } from '../../hooks/use-toast';
import { queryClient } from '../../stores/query-client';
import { userResourceProgressOptions } from '../../queries/resource-progress';
import { useAuth } from '../../hooks/use-auth';
type BulkUpdateResourceProgressBody = {
done: string[];
@@ -23,27 +28,38 @@ export function PersonalizedRoadmap(props: PersonalizedRoadmapProps) {
const { roadmapId } = props;
const toast = useToast();
const currentUser = useAuth();
const [isModalOpen, setIsModalOpen] = useState(false);
const {
mutate: bulkUpdateResourceProgress,
isPending: isBulkUpdating,
isSuccess: isBulkUpdateSuccess,
} = useMutation(
{
mutationFn: (body: BulkUpdateResourceProgressBody) => {
return httpPost(`/v1-bulk-update-resource-progress/${roadmapId}`, body);
},
onError: (error) => {
toast.error(
error?.message ?? 'Something went wrong, please try again.',
);
},
},
const { data: userResourceProgress } = useQuery(
userResourceProgressOptions('roadmap', roadmapId),
queryClient,
);
const { generatePersonalizedRoadmap } = usePersonalizedRoadmap({
const { mutate: bulkUpdateResourceProgress, isPending: isBulkUpdating } =
useMutation(
{
mutationFn: (body: BulkUpdateResourceProgressBody) => {
return httpPost(
`/v1-bulk-update-resource-progress/${roadmapId}`,
body,
);
},
onError: (error) => {
toast.error(
error?.message ?? 'Something went wrong, please try again.',
);
},
onSuccess: () => {
queryClient.invalidateQueries(
userResourceProgressOptions('roadmap', roadmapId),
);
},
},
queryClient,
);
const { generatePersonalizedRoadmap, status } = usePersonalizedRoadmap({
roadmapId,
onStart: () => {
setIsModalOpen(false);
@@ -55,6 +71,10 @@ export function PersonalizedRoadmap(props: PersonalizedRoadmapProps) {
});
},
onFinish: (data) => {
console.log('-'.repeat(20));
console.log('onFinish', data);
console.log('-'.repeat(20));
bulkUpdateResourceProgress({
skipped: data.topicIds,
learning: [],
@@ -64,21 +84,65 @@ export function PersonalizedRoadmap(props: PersonalizedRoadmapProps) {
},
});
const { mutate: clearResourceProgress, isPending: isClearing } = useMutation(
{
mutationFn: () => {
return httpPost(`/v1-clear-resource-progress`, {
resourceId: roadmapId,
resourceType: 'roadmap',
});
},
onError: (error) => {
toast.error(
error?.message ?? 'Something went wrong, please try again.',
);
},
onSuccess: () => {
toast.success('Progress cleared successfully.');
localStorage.removeItem(
`roadmap-${roadmapId}-${currentUser?.id}-progress`,
);
localStorage.removeItem(
`roadmap-${roadmapId}-${currentUser?.id}-favorite`,
);
window.location.reload();
},
},
queryClient,
);
const isGenerating = status !== 'idle' || isBulkUpdating || isClearing;
return (
<>
{isModalOpen && (
<PersonalizedRoadmapModal
roadmapId={roadmapId}
onClose={() => setIsModalOpen(false)}
onSubmit={generatePersonalizedRoadmap}
onSubmit={(information) => {
const { skipped = [] } = userResourceProgress ?? {};
for (const topicId of skipped) {
renderTopicProgress(topicId, 'pending');
}
generatePersonalizedRoadmap(information);
}}
onClearProgress={() => {
setIsModalOpen(false);
clearResourceProgress();
}}
/>
)}
<button
className="group inline-flex items-center gap-1.5 border-b-2 border-b-transparent px-2 pb-2.5 text-sm font-normal text-gray-400 transition-colors hover:text-gray-700"
onClick={() => setIsModalOpen(true)}
disabled={isGenerating}
>
<PersonStandingIcon className="h-4 w-4 shrink-0" />
{isGenerating ? (
<Loader2Icon className="h-4 w-4 shrink-0 animate-spin" />
) : (
<PersonStandingIcon className="h-4 w-4 shrink-0" />
)}
<span>Personalized</span>
</button>
</>

View File

@@ -1,13 +1,14 @@
import { PersonStandingIcon } from 'lucide-react';
import { PersonStandingIcon, XIcon } from 'lucide-react';
import { useId, useState, type FormEvent } from 'react';
type PersonalizedRoadmapFormProps = {
info?: string;
onSubmit: (info: string) => void;
onClearProgress: () => void;
};
export function PersonalizedRoadmapForm(props: PersonalizedRoadmapFormProps) {
const { info: defaultInfo, onSubmit } = props;
const { info: defaultInfo, onSubmit, onClearProgress } = props;
const [info, setInfo] = useState(defaultInfo || '');
const infoFieldId = useId();
@@ -34,7 +35,15 @@ export function PersonalizedRoadmapForm(props: PersonalizedRoadmapFormProps) {
/>
</div>
<div className="mt-2 flex items-center justify-end">
<div className="mt-2 grid grid-cols-2 gap-2">
<button
type="button"
className="flex items-center gap-2 rounded-xl border border-gray-200 p-2 px-4 text-gray-600 hover:bg-gray-100 focus:outline-none"
onClick={onClearProgress}
>
<XIcon className="h-4 w-4" />
Clear Progress
</button>
<button
type="submit"
className="flex items-center gap-2 rounded-xl bg-black p-2 px-4 text-white hover:opacity-90 focus:outline-none"

View File

@@ -4,17 +4,20 @@ import { Modal } from '../Modal';
import { PersonalizedRoadmapForm } from './PersonalizedRoadmapForm';
type PersonalizedRoadmapModalProps = {
roadmapId: string;
onClose: () => void;
onSubmit: (information: string) => void;
onClearProgress: () => void;
};
export function PersonalizedRoadmapModal(props: PersonalizedRoadmapModalProps) {
const { roadmapId, onClose, onSubmit } = props;
const { onClose, onSubmit, onClearProgress } = props;
return (
<Modal onClose={onClose} bodyClassName="rounded-2xl">
<PersonalizedRoadmapForm onSubmit={onSubmit} />
<PersonalizedRoadmapForm
onSubmit={onSubmit}
onClearProgress={onClearProgress}
/>
</Modal>
);
}

View File

@@ -206,7 +206,7 @@ export async function getResourceProgress(
return progress;
}
async function loadFreshProgress(
export async function loadFreshProgress(
resourceType: ResourceType,
resourceId: string,
) {