From 298876a2690a33b6fb52730f9a4b316b5bbf0cdd Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Fri, 12 Sep 2025 21:50:33 +0200 Subject: [PATCH] fix(lib): fix user_created reset when updating other users profile marker (#380) * fix user_created new set when updating other users profile marker * fix same issue on different places * fix linting * fix tests --- .../Map/Subcomponents/ItemFormPopup.tsx | 4 +-- .../Map/hooks/useSelectPosition.tsx | 10 ++----- .../Components/Profile/ItemFunctions.spec.tsx | 30 +++++++++++-------- lib/src/Components/Profile/ProfileForm.tsx | 4 +-- lib/src/Components/Profile/ProfileView.tsx | 6 ++-- lib/src/Components/Profile/itemFunctions.ts | 10 +++---- 6 files changed, 31 insertions(+), 33 deletions(-) diff --git a/lib/src/Components/Map/Subcomponents/ItemFormPopup.tsx b/lib/src/Components/Map/Subcomponents/ItemFormPopup.tsx index 534336a3..cbc9ee71 100644 --- a/lib/src/Components/Map/Subcomponents/ItemFormPopup.tsx +++ b/lib/src/Components/Map/Subcomponents/ItemFormPopup.tsx @@ -127,14 +127,14 @@ export function ItemFormPopup(props: Props) { const itemWithLayer = { ...result.data, layer: popupForm.layer, - user_created: user ?? undefined, + user_created: formItem.user_created, } updateItem(itemWithLayer) } return result.success }, - [popupForm, handleApiOperation, updateItem, user], + [popupForm, handleApiOperation, updateItem], ) // Create new item or update existing user profile diff --git a/lib/src/Components/Map/hooks/useSelectPosition.tsx b/lib/src/Components/Map/hooks/useSelectPosition.tsx index 26435915..49edc8ea 100644 --- a/lib/src/Components/Map/hooks/useSelectPosition.tsx +++ b/lib/src/Components/Map/hooks/useSelectPosition.tsx @@ -11,8 +11,6 @@ import { createContext, useContext, useEffect, useState, useCallback } from 'react' import { toast } from 'react-toastify' -import { useAuth } from '#components/Auth/useAuth' - import { useUpdateItem } from './useItems' import { useLayers } from './useLayers' import { useHasUserPermission } from './usePermissions' @@ -49,7 +47,6 @@ function useSelectPositionManager(): { const updateItem = useUpdateItem() const hasUserPermission = useHasUserPermission() const layers = useLayers() - const { user } = useAuth() // Handle API operations with consistent error handling and return response data const handleApiOperation = useCallback( @@ -144,7 +141,7 @@ function useSelectPositionManager(): { if (result.success && result.data) { // Find the layer object by ID from server response const layer = layers.find((l) => l.id === (result.data!.layer as unknown as string)) - const itemWithLayer = { ...result.data, layer, user_created: user ?? undefined } + const itemWithLayer = { ...result.data, layer, user_created: updatedItem.user_created } updateItem(itemWithLayer) await linkItem(updatedItem.id) setSelectPosition(null) @@ -178,9 +175,8 @@ function useSelectPositionManager(): { ) if (result.success && result.data) { - // Find the layer object by ID from server response const layer = layers.find((l) => l.id === (result.data!.layer as unknown as string)) - const itemWithLayer = { ...result.data, layer, user_created: user ?? undefined } + const itemWithLayer = { ...result.data, layer, user_created: updatedItem.user_created } updateItem(itemWithLayer) } } @@ -206,7 +202,7 @@ function useSelectPositionManager(): { if (result.success && result.data) { // Find the layer object by ID from server response const layer = layers.find((l) => l.id === (result.data!.layer as unknown as string)) - const itemWithLayer = { ...result.data, layer, user_created: user ?? undefined } + const itemWithLayer = { ...result.data, layer, user_created: markerClicked.user_created } updateItem(itemWithLayer) } } diff --git a/lib/src/Components/Profile/ItemFunctions.spec.tsx b/lib/src/Components/Profile/ItemFunctions.spec.tsx index 9644e507..d220780c 100644 --- a/lib/src/Components/Profile/ItemFunctions.spec.tsx +++ b/lib/src/Components/Profile/ItemFunctions.spec.tsx @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { describe, it, expect, vi } from 'vitest' +import { describe, it, expect, vi, beforeEach } from 'vitest' import { linkItem } from './itemFunctions' @@ -22,12 +22,6 @@ vi.mock('react-toastify', () => ({ describe('linkItem', () => { const id = 'some-id' let updateApi: (item: Partial) => Promise = vi.fn() - const mockUser = { - id: 'user-1', - first_name: 'Test', - last_name: 'User', - email: 'test@example.com', - } const item: Item = { layer: { id: 'test-layer-id', @@ -75,11 +69,16 @@ describe('linkItem', () => { describe('api rejects', () => { it('toasts an error', async () => { - updateApi = vi.fn().mockRejectedValue('autsch') - await linkItem(id, item, updateItem, mockUser) - expect(toastUpdateMock).toHaveBeenCalledWith(123, expect.objectContaining({ type: 'error' })) + updateApi = vi.fn().mockRejectedValue(new Error('autsch')) + await linkItem(id, item, updateItem) + expect(toastUpdateMock).toHaveBeenCalledWith( + 123, + expect.objectContaining({ + type: 'error', + render: 'autsch', + }), + ) expect(updateItem).not.toHaveBeenCalled() - expect(toastSuccessMock).not.toHaveBeenCalled() }) }) @@ -92,16 +91,21 @@ describe('linkItem', () => { } updateApi = vi.fn().mockResolvedValue(serverResponse) - await linkItem(id, item, updateItem, mockUser) + await linkItem(id, item, updateItem) expect(toastUpdateMock).toHaveBeenCalledWith( 123, - expect.objectContaining({ type: 'success' }), + expect.objectContaining({ + type: 'success', + render: 'Item linked', + }), ) expect(updateItem).toHaveBeenCalledWith( expect.objectContaining({ ...serverResponse, layer: item.layer, + relations: [{ items_id: item.id, related_items_id: id }], + user_created: item.user_created, }), ) }) diff --git a/lib/src/Components/Profile/ProfileForm.tsx b/lib/src/Components/Profile/ProfileForm.tsx index 79e1a423..b4d82862 100644 --- a/lib/src/Components/Profile/ProfileForm.tsx +++ b/lib/src/Components/Profile/ProfileForm.tsx @@ -198,8 +198,8 @@ export function ProfileForm() { state={state} setState={setState} updatePermission={updatePermission} - linkItem={(id: string) => linkItem(id, item, updateItem, user)} - unlinkItem={(id: string) => unlinkItem(id, item, updateItem, user)} + linkItem={(id: string) => linkItem(id, item, updateItem)} + unlinkItem={(id: string) => unlinkItem(id, item, updateItem)} setUrlParams={setUrlParams} > )} diff --git a/lib/src/Components/Profile/ProfileView.tsx b/lib/src/Components/Profile/ProfileView.tsx index a1ce365d..498f0347 100644 --- a/lib/src/Components/Profile/ProfileView.tsx +++ b/lib/src/Components/Profile/ProfileView.tsx @@ -12,7 +12,6 @@ import { useEffect, useState } from 'react' import { useMap } from 'react-leaflet' import { useLocation, useNavigate } from 'react-router-dom' -import { useAuth } from '#components/Auth/useAuth' import { useClusterRef } from '#components/Map/hooks/useClusterRef' import { useItems, useRemoveItem, useUpdateItem } from '#components/Map/hooks/useItems' import { useLayers } from '#components/Map/hooks/useLayers' @@ -52,7 +51,6 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi const map = useMap() const selectPosition = useSelectPosition() const removeItem = useRemoveItem() - const { user } = useAuth() const tags = useTags() const navigate = useNavigate() const hasUserPermission = useHasUserPermission() @@ -210,8 +208,8 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi needs={needs} relations={relations} updatePermission={updatePermission} - linkItem={(id) => linkItem(id, item, updateItem, user)} - unlinkItem={(id) => unlinkItem(id, item, updateItem, user)} + linkItem={(id) => linkItem(id, item, updateItem)} + unlinkItem={(id) => unlinkItem(id, item, updateItem)} /> )} diff --git a/lib/src/Components/Profile/itemFunctions.ts b/lib/src/Components/Profile/itemFunctions.ts index d04ae117..4c229c8b 100644 --- a/lib/src/Components/Profile/itemFunctions.ts +++ b/lib/src/Components/Profile/itemFunctions.ts @@ -116,7 +116,7 @@ export const submitNewItem = async ( setAddItemPopupType('') } -export const linkItem = async (id: string, item: Item, updateItem, user) => { +export const linkItem = async (id: string, item: Item, updateItem) => { const newRelations = item.relations ?? [] newRelations?.push({ items_id: item.id, related_items_id: id }) const updatedItem = { id: item.id, relations: newRelations } @@ -139,13 +139,13 @@ export const linkItem = async (id: string, item: Item, updateItem, user) => { ...result.data, layer, relations: newRelations, - user_created: user ?? undefined, + user_created: item.user_created, } updateItem(itemWithLayer) } } -export const unlinkItem = async (id: string, item: Item, updateItem, user) => { +export const unlinkItem = async (id: string, item: Item, updateItem) => { const newRelations = item.relations?.filter((r) => r.related_items_id !== id) const updatedItem = { id: item.id, relations: newRelations } @@ -163,7 +163,7 @@ export const unlinkItem = async (id: string, item: Item, updateItem, user) => { if (result.success && result.data) { // Find the layer object by ID from server response or use existing layer const layer = item.layer - const itemWithLayer = { ...result.data, layer, user_created: user ?? undefined } + const itemWithLayer = { ...result.data, layer, user_created: item.user_created } updateItem(itemWithLayer) } } @@ -308,7 +308,7 @@ export const onUpdateItem = async ( layer: item.layer, markerIcon: state.marker_icon, gallery: state.gallery, - user_created: user ?? undefined, + user_created: item.user_created, } updateItem(itemWithLayer) navigate(`/item/${item.id}${params && '?' + params}`)