diff options
Diffstat (limited to 'Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx')
-rw-r--r-- | Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx b/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx new file mode 100644 index 00000000..e4bc07d1 --- /dev/null +++ b/Timeline/ClientApp/src/app/timeline/TimelineInfoCard.tsx @@ -0,0 +1,109 @@ +import React from 'react'; +import clsx from 'clsx'; +import { + Dropdown, + DropdownToggle, + DropdownMenu, + DropdownItem, + Button, +} from 'reactstrap'; +import { useTranslation } from 'react-i18next'; +import { fromEvent } from 'rxjs'; + +import { + timelineVisibilityTooltipTranslationMap, + TimelineInfo, +} from '../data/timeline'; +import { TimelineCardComponentProps } from './TimelinePageTemplateUI'; + +export type OrdinaryTimelineManageItem = 'delete'; + +export type TimelineInfoCardProps = TimelineCardComponentProps< + TimelineInfo, + OrdinaryTimelineManageItem +>; + +const TimelineInfoCard: React.FC<TimelineInfoCardProps> = (props) => { + const { onHeight, onManage } = props; + + const { t } = useTranslation(); + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const containerRef = React.useRef<HTMLDivElement>(null!); + + const notifyHeight = React.useCallback((): void => { + if (onHeight) { + onHeight(containerRef.current.getBoundingClientRect().height); + } + }, [onHeight]); + + React.useEffect(() => { + const subscription = fromEvent(window, 'resize').subscribe(notifyHeight); + return () => subscription.unsubscribe(); + }); + + const [manageDropdownOpen, setManageDropdownOpen] = React.useState<boolean>( + false + ); + const toggleManageDropdown = React.useCallback( + (): void => setManageDropdownOpen((old) => !old), + [] + ); + + return ( + <div + ref={containerRef} + className={clsx('rounded border p-2 bg-light', props.className)} + onTransitionEnd={notifyHeight} + > + <h3 className="text-primary mx-3 d-inline-block align-middle"> + {props.timeline.name} + </h3> + <div className="d-inline-block align-middle"> + <img + src={props.timeline.owner._links.avatar} + onLoad={notifyHeight} + className="avatar small rounded-circle" + /> + {props.timeline.owner.nickname} + <small className="ml-3 text-secondary"> + @{props.timeline.owner.username} + </small> + </div> + <p className="mb-0">{props.timeline.description}</p> + <small className="mt-1 d-block"> + {t(timelineVisibilityTooltipTranslationMap[props.timeline.visibility])} + </small> + <div className="text-right mt-2"> + {onManage != null ? ( + <Dropdown isOpen={manageDropdownOpen} toggle={toggleManageDropdown}> + <DropdownToggle outline color="primary"> + {t('timeline.manage')} + </DropdownToggle> + <DropdownMenu> + <DropdownItem onClick={() => onManage('property')}> + {t('timeline.manageItem.property')} + </DropdownItem> + <DropdownItem onClick={props.onMember}> + {t('timeline.manageItem.member')} + </DropdownItem> + <DropdownItem divider /> + <DropdownItem + className="text-danger" + onClick={() => onManage('delete')} + > + {t('timeline.manageItem.delete')} + </DropdownItem> + </DropdownMenu> + </Dropdown> + ) : ( + <Button color="primary" outline onClick={props.onMember}> + {t('timeline.memberButton')} + </Button> + )} + </div> + </div> + ); +}; + +export default TimelineInfoCard; |