= ({
description="Select a user from the list to view their competences"
style={{ marginTop: 60 }}
/>
- ) : loading ? (
+ ) : loading || isPolling ? (
= ({ userId }) => {
const environment = useEnvironment();
- const [spaceCompetences, setSpaceCompetences] = useState([]);
- const [loading, setLoading] = useState(true);
+ const queryClient = useQueryClient();
+ const { data: spaceCompetences = [], isLoading } = useSpaceCompetences(environment.spaceId);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedCompetence, setSelectedCompetence] = useState(null);
const [claiming, setClaiming] = useState(false);
const [form] = Form.useForm();
- useEffect(() => {
- loadSpaceCompetences(true); // Initial load with loading indicator
-
- // Poll for updates every 5 seconds (without loading indicator)
- const interval = setInterval(() => {
- loadSpaceCompetences(false);
- }, 5000);
-
- return () => clearInterval(interval);
- }, [environment.spaceId]);
-
- const loadSpaceCompetences = async (showLoading: boolean = false) => {
- if (showLoading) {
- setLoading(true);
- }
- try {
- const response = await fetch(`/api/spaces/${environment.spaceId}/competences`);
- if (response.ok) {
- const data = await response.json();
- setSpaceCompetences(data);
- } else {
- message.error('Failed to load space competences');
- }
- } catch (error) {
- message.error('Error loading space competences');
- } finally {
- if (showLoading) {
- setLoading(false);
- }
- }
- };
-
const showClaimModal = (competence: SpaceCompetence) => {
setSelectedCompetence(competence);
form.resetFields();
@@ -110,11 +79,8 @@ const SpaceCompetencesClaim: React.FC = ({ userId })
});
if (result.success) {
- setSpaceCompetences((prev) =>
- prev.map((comp) =>
- comp.id === selectedCompetence.id ? { ...comp, isClaimed: true } : comp,
- ),
- );
+ // Invalidate the cache to trigger a refetch
+ queryClient.invalidateQueries({ queryKey: ['spaceCompetences', environment.spaceId] });
message.success('Competence claimed successfully');
handleCancel();
} else {
@@ -133,9 +99,8 @@ const SpaceCompetencesClaim: React.FC = ({ userId })
const result = await unclaimSpaceCompetence({ userId, competenceId });
if (result.success) {
- setSpaceCompetences((prev) =>
- prev.map((comp) => (comp.id === competenceId ? { ...comp, isClaimed: false } : comp)),
- );
+ // Invalidate the cache to trigger a refetch
+ queryClient.invalidateQueries({ queryKey: ['spaceCompetences', environment.spaceId] });
message.success('Competence unclaimed successfully');
} else {
message.error(result.message);
@@ -240,7 +205,7 @@ const SpaceCompetencesClaim: React.FC = ({ userId })
- {loading ? (
+ {isLoading ? (
= ({ userId })
gap: '16px',
}}
>
-
+
) : (
= ({
initialUserCompetences,
userId,
}) => {
- const [userCompetences, setUserCompetences] = useState(initialUserCompetences);
+ const queryClient = useQueryClient();
+ const { data: userCompetences = initialUserCompetences, isLoading: isPolling } =
+ useUserCompetences(userId);
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingCompetence, setEditingCompetence] = useState(null);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
- useEffect(() => {
- // Poll for updates every 5 seconds
- const interval = setInterval(async () => {
- try {
- const result = await getUserCompetences(userId);
- if (result.success && result.data) {
- setUserCompetences(result.data);
- }
- } catch (error) {
- debugLog('Error polling user competences:', error);
- }
- }, 5000);
-
- return () => clearInterval(interval);
- }, [userId]);
-
const showModal = (competence?: UserCompetence) => {
if (competence) {
setEditingCompetence(competence);
@@ -124,11 +109,8 @@ const UserCompetencesList: React.FC = ({
});
if (result.success) {
- setUserCompetences((prev) =>
- prev.map((comp) =>
- comp.competenceId === editingCompetence.competenceId ? result.data : comp,
- ),
- );
+ // Invalidate the cache to trigger a refetch
+ queryClient.invalidateQueries({ queryKey: ['userCompetences', userId] });
message.success('Competence updated successfully');
} else {
message.error(result.message);
@@ -145,7 +127,8 @@ const UserCompetencesList: React.FC = ({
});
if (result.success) {
- setUserCompetences((prev) => [...prev, result.data]);
+ // Invalidate the cache to trigger a refetch
+ queryClient.invalidateQueries({ queryKey: ['userCompetences', userId] });
message.success('Competence added successfully');
} else {
message.error(result.message);
@@ -166,7 +149,8 @@ const UserCompetencesList: React.FC = ({
const result = await deleteUserCompetence({ userId, competenceId });
if (result.success) {
- setUserCompetences((prev) => prev.filter((comp) => comp.competenceId !== competenceId));
+ // Invalidate the cache to trigger a refetch
+ queryClient.invalidateQueries({ queryKey: ['userCompetences', userId] });
message.success('Competence deleted successfully');
} else {
message.error(result.message);
@@ -184,7 +168,8 @@ const UserCompetencesList: React.FC = ({
const result = await unclaimSpaceCompetence({ userId, competenceId });
if (result.success) {
- setUserCompetences((prev) => prev.filter((comp) => comp.competenceId !== competenceId));
+ // Invalidate the cache to trigger a refetch
+ queryClient.invalidateQueries({ queryKey: ['userCompetences', userId] });
message.success('Competence unclaimed successfully');
} else {
message.error(result.message);
@@ -307,7 +292,7 @@ const UserCompetencesList: React.FC = ({
columns={columns}
dataSource={userCompetences}
rowKey={(record) => record.competenceId}
- loading={loading}
+ loading={loading || isPolling}
pagination={{ pageSize: 10, position: ['bottomCenter'] }}
/>
diff --git a/src/management-system-v2/lib/competence/useOrganizationSpaceCompetences.ts b/src/management-system-v2/lib/competence/useOrganizationSpaceCompetences.ts
new file mode 100644
index 000000000..8d17a1270
--- /dev/null
+++ b/src/management-system-v2/lib/competence/useOrganizationSpaceCompetences.ts
@@ -0,0 +1,25 @@
+'use client';
+
+import { useQuery } from '@tanstack/react-query';
+import { getOrganizationSpaceCompetences } from '@/components/competence/actions/organization-competence-actions';
+
+/**
+ * Hook for polling organization space competences
+ * Automatically refetches every 5 seconds and on window focus
+ */
+export function useOrganizationSpaceCompetences(spaceId: string) {
+ return useQuery({
+ queryKey: ['organizationSpaceCompetences', spaceId],
+ queryFn: async () => {
+ const result = await getOrganizationSpaceCompetences(spaceId);
+ if (!result.success) {
+ throw new Error(result.message);
+ }
+ return result.data;
+ },
+ refetchInterval: 5000, // Poll every 5 seconds
+ enabled: !!spaceId, // Only fetch if spaceId is provided
+ refetchOnWindowFocus: true,
+ refetchOnReconnect: true,
+ });
+}
diff --git a/src/management-system-v2/lib/competence/useSpaceCompetences.ts b/src/management-system-v2/lib/competence/useSpaceCompetences.ts
new file mode 100644
index 000000000..8dacbc1d5
--- /dev/null
+++ b/src/management-system-v2/lib/competence/useSpaceCompetences.ts
@@ -0,0 +1,24 @@
+'use client';
+
+import { useQuery } from '@tanstack/react-query';
+
+/**
+ * Hook for polling space competences from API endpoint
+ * Automatically refetches every 5 seconds and on window focus
+ */
+export function useSpaceCompetences(spaceId: string) {
+ return useQuery({
+ queryKey: ['spaceCompetences', spaceId],
+ queryFn: async () => {
+ const response = await fetch(`/api/spaces/${spaceId}/competences`);
+ if (!response.ok) {
+ throw new Error('Failed to load space competences');
+ }
+ return response.json();
+ },
+ refetchInterval: 5000, // Poll every 5 seconds
+ enabled: !!spaceId, // Only fetch if spaceId is provided
+ refetchOnWindowFocus: true,
+ refetchOnReconnect: true,
+ });
+}
diff --git a/src/management-system-v2/lib/competence/useUserCompetences.ts b/src/management-system-v2/lib/competence/useUserCompetences.ts
new file mode 100644
index 000000000..75b59fd3e
--- /dev/null
+++ b/src/management-system-v2/lib/competence/useUserCompetences.ts
@@ -0,0 +1,25 @@
+'use client';
+
+import { useQuery } from '@tanstack/react-query';
+import { getUserCompetences } from '@/components/competence/actions/organization-competence-actions';
+
+/**
+ * Hook for polling user competences
+ * Automatically refetches every 5 seconds and on window focus
+ */
+export function useUserCompetences(userId: string) {
+ return useQuery({
+ queryKey: ['userCompetences', userId],
+ queryFn: async () => {
+ const result = await getUserCompetences(userId);
+ if (!result.success) {
+ throw new Error(result.message);
+ }
+ return result.data;
+ },
+ refetchInterval: 5000, // Poll every 5 seconds
+ enabled: !!userId, // Only fetch if userId is provided
+ refetchOnWindowFocus: true,
+ refetchOnReconnect: true,
+ });
+}