import React, { useEffect, useState } from 'react' import Link from 'next/link' import { useRouter } from 'next/router' import { useSnapshot } from 'valtio' import { useTranslation } from 'next-i18next' import Linkify from 'react-linkify' import LiteYouTubeEmbed from 'react-lite-youtube-embed' import classNames from 'classnames' import reactStringReplace from 'react-string-replace' import sanitizeHtml from 'sanitize-html' import * as AlertDialog from '@radix-ui/react-alert-dialog' import Button from '~components/Button' import CharLimitedFieldset from '~components/CharLimitedFieldset' import RaidDropdown from '~components/RaidDropdown' import TextFieldset from '~components/TextFieldset' import { accountState } from '~utils/accountState' import { appState } from '~utils/appState' import { formatTimeAgo } from '~utils/timeAgo' import CheckIcon from '~public/icons/Check.svg' import CrossIcon from '~public/icons/Cross.svg' import EditIcon from '~public/icons/Edit.svg' import './index.scss' import { youtube } from '~utils/youtube' // Props interface Props { party?: Party new: boolean editable: boolean updateCallback: (name?: string, description?: string, raid?: Raid) => void deleteCallback: ( event: React.MouseEvent ) => void } const PartyDetails = (props: Props) => { const { party, raids } = useSnapshot(appState) const { t } = useTranslation('common') const router = useRouter() const locale = router.locale || 'en' const nameInput = React.createRef() const descriptionInput = React.createRef() const [open, setOpen] = useState(false) const [raidSlug, setRaidSlug] = useState('') const [embeddedDescription, setEmbeddedDescription] = useState() const readOnlyClasses = classNames({ PartyDetails: true, ReadOnly: true, Visible: !open, }) const editableClasses = classNames({ PartyDetails: true, Editable: true, Visible: open, }) const emptyClasses = classNames({ EmptyDetails: true, Visible: true, }) const userClass = classNames({ user: true, empty: !party.user, }) const linkClass = classNames({ wind: party && party.element == 1, fire: party && party.element == 2, water: party && party.element == 3, earth: party && party.element == 4, dark: party && party.element == 5, light: party && party.element == 6, }) const [errors, setErrors] = useState<{ [key: string]: string }>({ name: '', description: '', }) function handleInputChange(event: React.ChangeEvent) { event.preventDefault() const { name, value } = event.target let newErrors = errors setErrors(newErrors) } function handleTextAreaChange(event: React.ChangeEvent) { event.preventDefault() const { name, value } = event.target let newErrors = errors setErrors(newErrors) } useEffect(() => { // Extract the video IDs from the description if (party.description) { // sanitizeHtml(party.description) const videoIds = extractYoutubeVideoIds(party.description) // Fetch the video titles for each ID const fetchPromises = videoIds.map(({ id }) => fetchYoutubeData(id)) // Wait for all the video titles to be fetched Promise.all(fetchPromises).then((videoTitles) => { // YouTube regex const youtubeUrlRegex = /https:\/\/www\.youtube\.com\/watch\?v=([\w-]+)/g // Replace the video URLs in the description with LiteYoutubeEmbed elements const newDescription = reactStringReplace( party.description, youtubeUrlRegex, (match, i) => ( ) ) // Update the state with the new description setEmbeddedDescription(newDescription) }) } }, [party.description]) async function fetchYoutubeData(videoId: string) { return await youtube .getVideoById(videoId, { maxResults: 1 }) .then((data) => data.items[0].snippet.localized.title) } function toggleDetails() { setOpen(!open) } function receiveRaid(slug?: string) { if (slug) setRaidSlug(slug) } function updateDetails(event: React.MouseEvent) { const nameValue = nameInput.current?.value const descriptionValue = descriptionInput.current?.value const raid = raids.find((raid) => raid.slug === raidSlug) props.updateCallback(nameValue, descriptionValue, raid) toggleDetails() } function extractYoutubeVideoIds(text: string) { // Create a regular expression to match Youtube URLs in the text const youtubeUrlRegex = /https:\/\/www\.youtube\.com\/watch\?v=([\w-]+)/g // Initialize an array to store the video IDs const videoIds = [] // Use the regular expression to find all the Youtube URLs in the text let match while ((match = youtubeUrlRegex.exec(text)) !== null) { // Extract the video ID from the URL const videoId = match[1] // Add the video ID to the array, along with the character position of the URL videoIds.push({ id: videoId, url: match[0], position: match.index, }) } // Return the array of video IDs return videoIds } const userImage = (picture?: string, element?: string) => { if (picture && element) return ( {picture} ) else return
} const userBlock = (username?: string, picture?: string, element?: string) => { return (
{userImage(picture, element)} {username ? username : t('no_user')}
) } const renderUserBlock = () => { let username, picture, element if (accountState.account.authorized && props.new) { username = accountState.account.user?.username picture = accountState.account.user?.picture element = accountState.account.user?.element } else if (party.user && !props.new) { username = party.user.username picture = party.user.avatar.picture element = party.user.avatar.element } if (username && picture && element) { return linkedUserBlock(username, picture, element) } else if (!props.new) { return userBlock() } } const linkedUserBlock = ( username?: string, picture?: string, element?: string ) => { return ( ) } const linkedRaidBlock = (raid: Raid) => { return ( ) } const deleteButton = () => { if (party.editable) { return ( {t('buttons.delete')} {t('modals.delete_team.title')} {t('modals.delete_team.description')}
{t('modals.delete_team.buttons.cancel')} props.deleteCallback(e)} > {t('modals.delete_team.buttons.confirm')}
) } else { return '' } } const editable = (
{router.pathname !== '/new' ? deleteButton() : ''}
) const readOnly = (
{embeddedDescription}
) return (

{party.name ? party.name : 'Untitled'}

{renderUserBlock()} {party.raid ? linkedRaidBlock(party.raid) : ''} {party.created_at != '' ? ( ) : ( '' )}
{party.editable ? (
{readOnly} {editable}
) } export default PartyDetails