import { memo, useCallback, useMemo, useState } from 'react' import { useRangesActionsContext } from '../context/ranges-context' import { Change, DeleteOperation, EditOperation, } from '../../../../../types/change' import { useTranslation } from 'react-i18next' import classnames from 'classnames' import { usePermissionsContext } from '@/features/ide-react/context/permissions-context' import { FormatTimeBasedOnYear } from '@/shared/components/format-time-based-on-year' import { useChangesUsersContext } from '../context/changes-users-context' import { ReviewPanelChangeUser } from './review-panel-change-user' import { ReviewPanelEntry } from './review-panel-entry' import { useModalsContext } from '@/features/ide-react/context/modals-context' import { ExpandableContent } from './review-panel-expandable-content' import { useUserContext } from '@/shared/context/user-context' import { ChangeAction } from '@/features/review-panel-new/components/review-panel-change-action' import { AddIcon, DeleteIcon, EditIcon, } from '@/features/review-panel-new/components/review-panel-action-icons' export const ReviewPanelChange = memo<{ change: Change aggregate?: Change top?: number editable?: boolean docId: string hoverRanges?: boolean hovered?: boolean handleEnter?: (changeId: string) => void handleLeave?: () => void }>( ({ change, aggregate, top, docId, hoverRanges, editable = true, hovered, handleEnter, handleLeave, }) => { const { t } = useTranslation() const { acceptChanges, rejectChanges } = useRangesActionsContext() const permissions = usePermissionsContext() const changesUsers = useChangesUsersContext() const { showGenericMessageModal } = useModalsContext() const user = useUserContext() const [accepting, setAccepting] = useState(false) const acceptHandler = useCallback(async () => { setAccepting(true) try { if (aggregate) { await acceptChanges(change.id, aggregate.id) } else { await acceptChanges(change.id) } } catch (err) { showGenericMessageModal( t('accept_change_error_title'), t('accept_change_error_description') ) } finally { setAccepting(false) } }, [acceptChanges, aggregate, change.id, showGenericMessageModal, t]) const rejectHandler = useCallback(async () => { if (aggregate) { await rejectChanges(change.id, aggregate.id) } else { await rejectChanges(change.id) } }, [aggregate, change, rejectChanges]) const translations = useMemo( () => ({ accept_change: t('accept_change'), reject_change: t('reject_change'), aggregate_changed: t('aggregate_changed'), aggregate_to: t('aggregate_to'), tracked_change_added: t('tracked_change_added'), tracked_change_deleted: t('tracked_change_deleted'), }), [t] ) const { handleMouseEnter, handleMouseLeave } = useMemo( () => ({ handleMouseEnter: handleEnter && (() => handleEnter(change.id)), handleMouseLeave: handleLeave && (() => handleLeave()), }), [change.id, handleEnter, handleLeave] ) if (!changesUsers) { // if users are not loaded yet, do not show "Unknown" user return null } const isChangeAuthor = change.metadata?.user_id === user.id const aggregateChange = aggregate && /\S/.test(aggregate.op.d) return (
{change.metadata?.ts && (
)}
{editable && (
{permissions.write && ( )} {(permissions.write || (permissions.trackedWrite && isChangeAuthor)) && ( )}
)}
{'i' in change.op && ( <> {aggregateChange ? : } {aggregateChange ? ( {translations.aggregate_changed}:{' '} {' '} {translations.aggregate_to}{' '} ) : ( {translations.tracked_change_added}:  )} )} {'d' in change.op && ( <> {translations.tracked_change_deleted}:  )}
) } ) ReviewPanelChange.displayName = 'ReviewPanelChange'