diff --git a/moon/apps/web/components/Issues/IssueDetailPage.tsx b/moon/apps/web/components/Issues/IssueDetailPage.tsx
index c11166e77..6dc997f19 100644
--- a/moon/apps/web/components/Issues/IssueDetailPage.tsx
+++ b/moon/apps/web/components/Issues/IssueDetailPage.tsx
@@ -78,7 +78,7 @@ export default function IssueDetailPage({ id }: { id: string }) {
useEffect(() => {
fetchDetail()
- }, [fetchDetail])
+ }, [fetchDetail, id])
const [_loadings, setLoadings] = useState([])
const router = useRouter()
diff --git a/moon/apps/web/components/Issues/IssueIndex.tsx b/moon/apps/web/components/Issues/IssueIndex.tsx
index c5581a98b..813355631 100644
--- a/moon/apps/web/components/Issues/IssueIndex.tsx
+++ b/moon/apps/web/components/Issues/IssueIndex.tsx
@@ -1,3 +1,5 @@
+'use client'
+
import { useState } from 'react'
import { useAtom } from 'jotai'
import { useRouter } from 'next/router'
@@ -32,7 +34,6 @@ export const IssueIndex = () => {
return (
<>
-
@@ -45,11 +46,10 @@ export const IssueIndex = () => {
-
+
-
>
@@ -101,7 +101,14 @@ export const NewIssueButton = () => {
const { scope } = useScope()
return (
-
+ // className: 'sticky top-0 z-50 bg-white'
+ },
+ ...dropdownArr,
+ { type: 'separator' },
+ {
+ type: 'item',
+ disabled: true,
+ label: Order
+ // className: 'sticky top-0 z-50 bg-white'
+ },
+ ...(dropdownItem as MenuItem[])
+ ]}
+ trigger={
+
+ {inside ? (
+ inside
+ ) : (
+ <>
+ {name}
+ >
+ )}
+
+ }
+ />
>
)
}
-export const ListItem = ({
- title,
- children,
- leftIcon,
- rightIcon,
- onClick
+// dropdownArr是不一样的,其他一样
+export const Dropdown = ({
+ name,
+ dropdownArr,
+ dropdownItem,
+ isChosen,
+ onOpen,
+ open,
+ inside
}: {
- title: string
- children?: ReactNode
- leftIcon?: ReactNode
- rightIcon?: ReactNode
- onClick?: () => void
+ name: string
+ dropdownArr: MenuItem[]
+ dropdownItem?: MenuItem[]
+ isChosen: boolean
+ onOpen?: (open: boolean) => void
+ open?: boolean
+ inside?: React.ReactNode
}) => {
+ const [query, setQuery] = useState('')
+ // const { scope } = useScope()
+ // const [sort] = useAtom(sortAtom({ scope, filter: 'sortPicker' }))
+ const isSearching = query.length > 0
+ const ref = useRef(null)
+
+ const DropdownSearch = () => (
+
+
+ {isSearching ? } /> : }
+
+ setQuery(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === 'Escape') {
+ setQuery('')
+ ref.current?.blur()
+ } else if (e.key === 'Enter') {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ }}
+ />
+
+ )
+
return (
<>
-
-
-
{leftIcon}
-
{
- e.stopPropagation()
- onClick?.()
- }}
- className='inner flex flex-col hover:cursor-pointer'
- >
- {title}
- {children}
-
-
-
-
+ {isChosen ? (
+ Filter by {name}
+ // className: 'sticky top-0 z-50 bg-white'
+ },
+ {
+ type: 'item',
+ label: ,
+ onSelect: (e) => e.preventDefault()
+ // className: 'sticky top-10 z-50 bg-white'
+ },
+ { type: 'separator' },
+ ...dropdownArr
+ ]}
+ trigger={
+
+
+ {inside ? (
+ inside
+ ) : (
+ <>
+ {name}
+ >
+ )}
+
+
+ }
+ />
+ ) : (
+ Filter by {name},
+ disabled: true
+ // className: 'sticky top-0 z-50 bg-white pt-4'
+ },
+ {
+ type: 'item',
+ label: ,
+ onSelect: (e) => e.preventDefault()
+ // className: 'sticky top-10 z-50 bg-white pt-4'
+ },
+ { type: 'separator' },
+ { type: 'heading', label: 'Group assignees' },
+ ...(dropdownItem as MenuItem[]),
+ { type: 'separator' },
+ { type: 'heading', label: 'Suggestions' },
+ ...dropdownArr
+ ]}
+ trigger={
+
+
+ {inside ? (
+ inside
+ ) : (
+ <>
+ {name}
+ >
+ )}
+
+
+ }
+ />
+ )}
>
)
}
+
+export const ListItem = memo(
+ ({
+ title,
+ children,
+ leftIcon,
+ rightIcon,
+ onClick
+ }: {
+ title: string
+ children?: ReactNode
+ leftIcon?: ReactNode
+ rightIcon?: ReactNode
+ onClick?: () => void
+ }) => {
+ return (
+ <>
+
+
+
{leftIcon}
+
{
+ e.stopPropagation()
+ onClick?.()
+ }}
+ className='inner flex flex-col hover:cursor-pointer'
+ >
+ {title}
+ {children}
+
+
+
+
+ >
+ )
+ }
+)
+ListItem.displayName = 'ListItem'
diff --git a/moon/apps/web/components/Issues/IssuesContent.tsx b/moon/apps/web/components/Issues/IssuesContent.tsx
index fa2d0bf56..c2850b239 100644
--- a/moon/apps/web/components/Issues/IssuesContent.tsx
+++ b/moon/apps/web/components/Issues/IssuesContent.tsx
@@ -1,19 +1,35 @@
-import React, { useCallback, useEffect, useState } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useInfiniteQuery } from '@tanstack/react-query'
+import { formatDistance, fromUnixTime } from 'date-fns'
import { useAtom } from 'jotai'
-import { PostApiIssueListData } from '@gitmono/types/generated'
+import { SyncOrganizationMember as Member, PostApiIssueListData } from '@gitmono/types/generated'
+import { Button, ChatBubbleIcon, CheckCircleFilledFlushIcon, ChevronDownIcon, OrderedListIcon } from '@gitmono/ui'
+import { Link } from '@gitmono/ui/Link'
+
+// import { MenuItem } from '@gitmono/ui/Menu'
import { EmptySearchResults } from '@/components/Feed/EmptySearchResults'
-import { IssueList } from '@/components/Issues/IssueList'
-import { filterAtom } from '@/components/Issues/utils/store'
+import {
+ Dropdown,
+ DropdownItemwithAvatar,
+ DropdownItemwithLabel,
+ DropdownOrder,
+ IssueList,
+ ListBanner,
+ ListItem
+} from '@/components/Issues/IssueList'
+import { filterAtom, sortAtom } from '@/components/Issues/utils/store'
import { useScope } from '@/contexts/scope'
import { useGetIssueLists } from '@/hooks/issues/useGetIssueLists'
+import { useSyncedMembers } from '@/hooks/useSyncedMembers'
import { apiErrorToast } from '@/utils/apiErrorToast'
+import { atomWithWebStorage } from '@/utils/atomWithWebStorage'
import { IndexPageInstantLoading } from '../IndexPages/components'
-import { IssueIndexEmptyState } from './IssueIndex'
import { Pagination } from './Pagenation'
+import { orderTags, tags } from './utils/consts'
+import { generateAllMenuItems, MenuConfig } from './utils/generateAllMenuItems'
interface Props {
getIssues?: ReturnType>
@@ -31,9 +47,17 @@ export interface Item {
updated_at: number
}
+export interface Label {
+ id: string
+ name: string
+ color: string
+ remarks: string
+ checked: boolean
+}
+
export function IssuesContent({ searching }: Props) {
- // TODO:rebuild bu useInfiniteQuery
const { mutate: issueLists } = useGetIssueLists()
+
const { scope } = useScope()
const [pageSize, _setPageSize] = useState(10)
@@ -46,6 +70,182 @@ export function IssuesContent({ searching }: Props) {
const [numTotal, setNumTotal] = useState(0)
+ const [sort, setSort] = useAtom(sortAtom({ scope, filter: 'sortPicker' }))
+
+ const orderAtom = useMemo(() => atomWithWebStorage(`${scope}:issue-order`, 'Newest'), [scope])
+
+ const [order, _setOrder] = useAtom(orderAtom)
+
+ const { members } = useSyncedMembers()
+
+ const MemberConfig: MenuConfig[] = [
+ {
+ key: 'Author',
+ isChosen: (item) => item.user.id === sort['Author'],
+ onSelectFactory: (item: Member) => (e: Event) => {
+ e.preventDefault()
+ if (item.user.id === sort['Author']) {
+ fetchData(1, pageSize)
+ setSort({
+ ...sort,
+ Author: ''
+ })
+ } else {
+ setIssueList(issueList.filter((i) => i.link === sort['Author']))
+ setSort({
+ ...sort,
+ Author: item.user.id
+ })
+ }
+ },
+ className: 'overflow-hidden',
+ labelFactory: (item: Member) =>
+ },
+ {
+ key: 'Assignees',
+ isChosen: (item: Member) => item.user.id === sort['Assignees'],
+ onSelectFactory: (item: Member) => (e: Event) => {
+ e.preventDefault()
+ if (item.user.id === sort['Assignees']) {
+ fetchData(1, pageSize)
+
+ setSort({
+ ...sort,
+ Assignees: ''
+ })
+ } else {
+ setIssueList(issueList.filter((i) => i.link === sort['Assignees']))
+ setSort({
+ ...sort,
+ Assignees: item.user.id
+ })
+ }
+ },
+ className: 'overflow-hidden',
+ labelFactory: (item: Member) =>
+ }
+ ]
+
+ const LabelConfig: MenuConfig