55ce772eaa
Add the "resources" section (?page=resources&projectId=): professions and companies assigned to a project, with the same lists, fields, texts and optimistic add/remove with rollback as the legacy web part. PnPjs is replaced by SharePoint REST through the app's IHttpClient so the bundle needs no new dependency: the same $select/$expand/$filter, PnP paging replaced by following odata.nextLink, adds as POST to items with the same body, deletes as POST with X-HTTP-Method DELETE and IF-MATCH *. Known legacy edge cases (temporary negative id) are kept and listed in the checklist. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
35 lines
1.0 KiB
TypeScript
35 lines
1.0 KiB
TypeScript
import * as React from 'react';
|
||
import { Button } from '@tnsu/ui-kit';
|
||
import { IAssignedResource } from './resourcesTypes';
|
||
import { RESOURCES_TEXTS } from './texts';
|
||
import styles from './ResourcesPage.module.scss';
|
||
|
||
const TEXTS = RESOURCES_TEXTS.assigned;
|
||
|
||
interface Props {
|
||
items: IAssignedResource[];
|
||
onRemove: (itemId: number) => void;
|
||
}
|
||
|
||
/** Правая колонка «Привязаны к проекту». */
|
||
export const AssignedPanel: React.FC<Props> = ({ items, onRemove }) => (
|
||
<div className={styles.panelColumn}>
|
||
<div className={styles.panelTitle}>{TEXTS.title}</div>
|
||
{items.length === 0 && <div className={styles.emptyMsg}>{TEXTS.empty}</div>}
|
||
{items.map((item) => (
|
||
<div key={item.id} className={styles.itemRow}>
|
||
<span className={styles.itemName}>{item.title}</span>
|
||
<Button
|
||
variant="danger"
|
||
size="sm"
|
||
title={TEXTS.remove}
|
||
aria-label={TEXTS.remove}
|
||
onClick={() => onRemove(item.id)}
|
||
>
|
||
−
|
||
</Button>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|