Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
247 changes: 117 additions & 130 deletions moon/apps/web/components/Issues/IssueDetailPage.tsx

Large diffs are not rendered by default.

89 changes: 34 additions & 55 deletions moon/apps/web/components/Issues/IssueNewPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import React, { useCallback, useMemo, useRef, useState } from 'react'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { ActionList, FormControl, SelectPanel, Stack, Text, TextInput } from '@primer/react'
import { ItemInput } from '@primer/react/lib/deprecated/ActionList'
import { useRouter } from 'next/router'
Expand All @@ -18,15 +18,13 @@ import { useScope } from '@/contexts/scope'
import { usePostIssueSubmit } from '@/hooks/issues/usePostIssueSubmit'
import { useGetCurrentUser } from '@/hooks/useGetCurrentUser'
import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember'
import { useSyncedMembers } from '@/hooks/useSyncedMembers'
import { useUploadHelpers } from '@/hooks/useUploadHelpers'
import { apiErrorToast } from '@/utils/apiErrorToast'
import { trimHtml } from '@/utils/trimHtml'

import { MemberAvatar } from '../MemberAvatar'
import { tags } from './utils/consts'
import { extractTextArray } from './utils/extractText'
import { pickWithReflect } from './utils/pickWithReflectDeep'
import { splitFun, useAvatars, useLabelMap, useLabels, useMemberMap } from './utils/sideEffect'

// import { OrganizationMember } from '@gitmono/types/generated'

Expand Down Expand Up @@ -54,39 +52,10 @@ export default function IssueNewPage() {
}
}, [user])

const splitFun = (el: React.ReactNode): string[] => {
return extractTextArray(el)
.flatMap((name) => name.split(',').map((n) => n.trim()))
.filter((n) => n.length > 0)
}

const { members } = useSyncedMembers()

const avatars: ItemInput[] = useMemo(
() =>
members?.map((i) => ({
groupId: 'end',
text: i.user.display_name,
leadingVisual: () => <MemberAvatar size='sm' member={i} />
})) || [],
[members]
)
const avatars = useAvatars()
// const [avatarTems, setAvatarItems] = useState<ItemInput[]>(avatars)

const labels: ItemInput[] = useMemo(
() =>
tags.map((i) => ({
text: i.description,
leadingVisual: () => (
<div
className='h-[14px] w-[14px] rounded-full border'
//eslint-disable-next-line react/forbid-dom-props
style={{ backgroundColor: i.color, borderColor: i.color }}
/>
)
})),
[]
)
const labels = useLabels()

const [isReactionPickerOpen, setIsReactionPickerOpen] = useState(false)
const set_to_loading = (index: number) => {
Expand Down Expand Up @@ -137,23 +106,9 @@ export default function IssueNewPage() {
upload: editorRef.current?.uploadAndAppendAttachments
})

const memberMap = useMemo(() => {
const map = new Map()

members?.forEach((i) => {
map.set(i.user.display_name, i)
})
return map
}, [members])

const labelMap = useMemo(() => {
const map = new Map()
const memberMap = useMemberMap()

tags.map((i) => {
map.set(i.description, i)
})
return map
}, [])
const labelMap = useLabelMap()

// const createGroup = (selected: ItemInput[]) => {
// setAvatarItems((prev) => {
Expand Down Expand Up @@ -315,7 +270,10 @@ export const BadgeItem = ({
selectPannelProps,
items,
children,
handleGroup
handleGroup,
open,
onOpenChange,
selected
}: {
title: string
selectPannelProps?: Omit<React.ComponentProps<typeof SelectPanel>, SelectPanelExcludedProps> & {
Expand All @@ -324,13 +282,34 @@ export const BadgeItem = ({
items: ItemInput[]
children?: (el: React.ReactNode) => React.ReactNode
handleGroup?: (selected: ItemInput[]) => void
open?: boolean
onOpenChange?: (open: boolean) => void
selected?: ItemInput[]
}) => {
// const { open, onOpenChange } = selectPannelProps ?? {}
// open有传,则是受控组件,没传就是非受控组件(内部管理)
const isControl = open !== undefined

const [control, setControl] = useState(false)

const currentOpen = isControl ? open : control

const [chose, setChose] = useState<ItemInput[]>([])

const [filter, setFilter] = React.useState('')

useEffect(() => {
selected && selected?.length !== 0 ? setChose([...selected]) : setChose([])
}, [selected])

const handleOpenChange = (nextOpen: boolean, _gesture?: any) => {
// 有onOpenChange就传递
onOpenChange?.(nextOpen)
if (!isControl) {
setControl(nextOpen)
}
}

const filteredItems = items.filter(
(item) =>
// design guidelines say to always show selected item in the list
Expand Down Expand Up @@ -359,8 +338,8 @@ export const BadgeItem = ({
</div>
)
}}
open={control}
onOpenChange={setControl}
open={currentOpen}
onOpenChange={(open, gesture) => handleOpenChange(open, gesture)}
items={filteredItems}
selected={chose}
onSelectedChange={(selected: ItemInput[]) => {
Expand All @@ -385,4 +364,4 @@ export const SideBarItem = ({ emptyState }: { emptyState: string }) => {
</div>
</>
)
}
}
69 changes: 44 additions & 25 deletions moon/apps/web/components/Issues/IssuesContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ export function IssuesContent({ searching }: Props) {

const router = useRouter()



const [openCurrent, setopenCurrent] = useAtom(issueOpenCurrentPage)
const [closeCurrent, setcloseCurrent] = useAtom(issueCloseCurrentPage)

Expand Down Expand Up @@ -416,7 +414,7 @@ export function IssuesContent({ searching }: Props) {
title={i.title}
leftIcon={getStatusIcon(i.status)}
rightIcon={<RightAvatar item={i} />}
onClick={() => router.push(`/${scope}/issue/${i.link}`)}
onClick={() => router.push(`/${scope}/issue/${i.link}/${i.id}`)}
>
<div className='text-xs text-[#59636e]'>
{i.link} · {i.author} {i.status}{' '}
Expand All @@ -426,21 +424,25 @@ export function IssuesContent({ searching }: Props) {
))
}}
</IssueList>
{numTotal > 10 && status === 'open' && (
<Pagination
currentPage={issueOpenCurrentPage}
totalNum={numTotal}
pageSize={pageSize}
onChange={(page: number) => handlePageChange(page)}
/>
{status === 'open' && (
<div className='mt-auto'>
<Pagination
currentPage={issueOpenCurrentPage}
totalNum={numTotal}
pageSize={pageSize}
onChange={(page: number) => handlePageChange(page)}
/>
</div>
)}
{numTotal > 10 && status === 'closed' && (
<Pagination
currentPage={issueCloseCurrentPage}
totalNum={numTotal}
pageSize={pageSize}
onChange={(page: number) => handlePageChange(page)}
/>
{status === 'closed' && (
<div className='mt-auto'>
<Pagination
currentPage={issueCloseCurrentPage}
totalNum={numTotal}
pageSize={pageSize}
onChange={(page: number) => handlePageChange(page)}
/>
</div>
)}
</>
)}
Expand All @@ -460,17 +462,34 @@ function IssueSearchList(_props: { searchIssueList?: Item[]; hideProject?: boole
export const RightAvatar = ({ item }: { item: ItemsType[number] }) => {
const shouldFetch = item.assignees.length > 0

const { data } = useGetOrganizationMember({ username: item.assignees[0], org: 'mega', enabled: shouldFetch })
const [index, setIndex] = useState(0)

const { data, error } = useGetOrganizationMember({
username: item.assignees[index],
org: 'mega',
enabled: shouldFetch
})

useEffect(() => {
if (index >= item.assignees.length) return
if (error) {
setIndex((prev) => prev + 1)
}
}, [error, index, item.assignees])

return (
<>
<div className='mr-10 flex w-[120px] items-center justify-between gap-10'>
{item.comment_num !== 0 && (
<div className='flex items-center gap-2 text-sm text-gray-500'>
<ChatBubbleIcon />
<span>{item.comment_num}</span>
</div>
)}
<div
style={{
visibility: `${item.comment_num === 0 ? 'hidden' : 'unset'}`
}}
className='flex items-center gap-2 text-sm text-gray-500'
>
<ChatBubbleIcon />
<span>{item.comment_num}</span>
</div>

{data && (
// <div>展示头像</div>
<MemberHovercard username={item.assignees[0]} side='top' align='end' member={data}>
Expand All @@ -480,4 +499,4 @@ export const RightAvatar = ({ item }: { item: ItemsType[number] }) => {
</div>
</>
)
}
}
Loading