Files
developer-roadmap/src/components/EditorRoadmap/EditorRoadmap.tsx
T
Kamran Ahmed 02e7373bcd feat: add floating chat on roadmap pages (#8765)
* Add floating chat

* Refactor roadmap ai chat to hook

* Chat inside floating chat

* Fix bulk update not working

* Add floating chat widget

* Add chat header buttons

* Show a default set of questions

* Populate chat questions at bottom

* Handle chat submission

* Add personalize popup

* Fix body scroll locking issue

* Add scroll to bottom functionality

* Fix focus issue on persona form

* Fix responsiveness of the floating chat

* Final implementation

* Height fixes

* Fix floating ui

* Upgrade flow in floating chat

* Upgrade responsive UI

* Authetnicated checks

* Responsive bottom bar
2025-06-10 19:43:06 +01:00

106 lines
2.7 KiB
TypeScript

import { useEffect, useState, type CSSProperties } from 'react';
import {
EditorRoadmapRenderer,
type RoadmapRendererProps,
} from './EditorRoadmapRenderer';
import { Spinner } from '../ReactIcons/Spinner';
import {
clearMigratedRoadmapProgress,
type ResourceType,
} from '../../lib/resource-progress';
import { httpGet } from '../../lib/http';
import { getUrlParams } from '../../lib/browser.ts';
import { RoadmapFloatingChat } from '../FrameRenderer/RoadmapFloatingChat.tsx';
type EditorRoadmapProps = {
resourceId: string;
resourceType?: ResourceType;
dimensions: {
width: number;
height: number;
};
};
export function EditorRoadmap(props: EditorRoadmapProps) {
const { resourceId, resourceType = 'roadmap', dimensions } = props;
const [hasSwitchedRoadmap, setHasSwitchedRoadmap] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [roadmapData, setRoadmapData] = useState<
Omit<RoadmapRendererProps, 'resourceId'> | undefined
>(undefined);
const loadRoadmapData = async () => {
setIsLoading(true);
const { r: switchRoadmapId } = getUrlParams();
const { response, error } = await httpGet<
Omit<RoadmapRendererProps, 'resourceId'>
>(
`${import.meta.env.PUBLIC_API_URL}/v1-official-roadmap/${switchRoadmapId || resourceId}`,
);
if (error) {
console.error(error);
return;
}
setRoadmapData(response);
setIsLoading(false);
setHasSwitchedRoadmap(!!switchRoadmapId);
};
useEffect(() => {
clearMigratedRoadmapProgress(resourceType, resourceId);
loadRoadmapData().finally();
}, [resourceId]);
const aspectRatio = dimensions.width / dimensions.height;
if (!roadmapData || isLoading) {
return (
<div
style={
!hasSwitchedRoadmap
? ({
'--aspect-ratio': aspectRatio,
} as CSSProperties)
: undefined
}
className={
'mt-5 flex aspect-[var(--aspect-ratio)] w-full flex-col justify-center'
}
>
<div className="flex w-full justify-center">
<Spinner
className="h-6 w-6 animate-spin sm:h-12 sm:w-12"
isDualRing={false}
/>
</div>
</div>
);
}
return (
<div
style={
!hasSwitchedRoadmap
? ({
'--aspect-ratio': aspectRatio,
} as CSSProperties)
: undefined
}
className={
'mt-5 flex aspect-[var(--aspect-ratio)] w-full flex-col justify-center'
}
>
<EditorRoadmapRenderer
{...roadmapData}
dimensions={dimensions}
resourceId={resourceId}
/>
<RoadmapFloatingChat roadmapId={resourceId} />
</div>
);
}