pinkmine/frontend/src/misc-components/issue-details-dialog.tsx
Pavel Gnedov b9899bc032 Настройка в react приложении профилей для разработки и продакшена
- для разработки включен hotreload
- на бакенде включен CORS
2023-07-03 08:06:01 +07:00

113 lines
No EOL
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import { RedmineTypes } from '../redmine-types';
import { observer } from 'mobx-react-lite';
import { Instance, types } from 'mobx-state-tree';
import * as IssueHrefNs from '../misc-components/issue-href';
import Css from './issue-details-dialog.module.css';
import * as UnreadedFlagNs from '../misc-components/unreaded-flag';
import { SetIssueReadingTimestamp } from '../utils/unreaded-provider';
import axios from 'axios';
import * as Luxon from 'luxon';
export const Store = types.model({
visible: types.boolean,
issue: types.frozen<RedmineTypes.ExtendedIssue>(),
unreadedFlagStore: types.maybe(UnreadedFlagNs.Store)
}).actions((self) => {
return {
hide: () => {
console.debug(`Issue details dialog hide: issue_id=${self.issue.id}`); // DEBUG
self.visible = false;
},
show: () => {
console.debug(`Issue details dialog show: issue_id=${self.issue.id}`); // DEBUG
self.visible = true;
if (self.unreadedFlagStore) {
self.unreadedFlagStore.read();
} else {
SetIssueReadingTimestamp(self.issue.id);
}
}
};
}).views((self) => {
return {
get displayStyle(): React.CSSProperties {
return {display: self.visible ? 'block' : 'none'};
}
};
});
export type Props = {
store: Instance<typeof Store>
};
export const IssueDetailsDialog = observer((props: Props): JSX.Element => {
const onUpdateClick = (e: React.MouseEvent) => {
const url = `${process.env.REACT_APP_BACKEND}redmine-event-emitter/append-issues`;
axios.post(url, [props.store.issue.id]);
};
const onCloseClick = (e: React.MouseEvent) => {
if (e.target !== e.currentTarget) return;
e.stopPropagation();
props.store.hide();
};
return (
<div className={Css.modal} style={props.store.displayStyle} onClick={onCloseClick}>
<div className={Css.modalContent}>
<h1>
<button onClick={onCloseClick}>close</button>
<button onClick={onUpdateClick}>force update</button>
<IssueHrefNs.IssueHref
id={props.store.issue?.id || -1}
subject={props.store.issue?.subject || ''}
tracker={props.store.issue?.tracker?.name || ''}
url={props.store.issue?.url?.url || ''}
/>
</h1>
<hr/>
<div>
<h2>Описание:</h2>
<pre>
{props.store.issue.description}
</pre>
</div>
<hr/>
<div>
<h2>Комментарии:</h2>
<Comments details={props.store.issue.journals || []} issue={props.store.issue}/>
</div>
</div>
</div>
);
});
export const Comments = (props: {details?: RedmineTypes.Journal[], issue: RedmineTypes.ExtendedIssue}): JSX.Element => {
const comments = props.details?.filter((detail) => {
return Boolean(detail.notes);
});
if (!comments) {
return <>No comments</>
}
const list = comments.map((detail) => {
const key = `issueid_${props.issue.id}_commentid_${detail.id}`;
return <Comment data={detail} key={key}/>
});
return (
<>{list}</>
);
}
export const Comment = (props: {data: RedmineTypes.Journal}): JSX.Element => {
const date = Luxon.DateTime.fromISO(props.data.created_on).toFormat("dd.MM.yyyy HH:mm");
return (
<>
<h3><span className={Css.dateField}>{date}</span> {props.data.user.name}:</h3>
<div>
<pre>
{props.data.notes || '-'}
</pre>
</div>
<hr/>
</>
);
}