Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Saved Segments variant D #4891

Draft
wants to merge 1 commit into
base: saved-segments/variant-c
Choose a base branch
from
Draft
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
4 changes: 2 additions & 2 deletions assets/js/dashboard/components/search-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ export const SearchInput = ({
)

useKeybind({
target: searchBoxRef.current,
target: document,
keyboardKey: 'Escape',
type: 'keyup',
handler: blurSearchBox,
shouldIgnoreWhen: [isModifierPressed]
})

useKeybind({
target: searchBoxRef.current,
target: document,
keyboardKey: '/',
type: 'keyup',
handler: focusSearchBox,
Expand Down
7 changes: 0 additions & 7 deletions assets/js/dashboard/nav-menu/filter-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,6 @@ export const FilterMenu = () => {
}}
target={dropdownRef.current}
/>
<div className="px-4 pb-1 pt-4">
<SearchInput
placeholderUnfocused="Press / to search"
className="w-full text-xs sm:text-xs"
onSearch={setSearch}
/>
</div>

<DropdownLinkGroup className="flex flex-row">
{columns.map((filterGroups, index) => (
Expand Down
259 changes: 96 additions & 163 deletions assets/js/dashboard/segments/segment-modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ const SegmentRow = ({
segmentDataVisible: boolean
toggleSegmentDataVisible: () => void
}) => {
const { query } = useQueryContext()
const navigate = useAppNavigate()
const { prefetchSegment, data, fetchSegment } = useSegmentPrefetch({
id
Expand All @@ -338,58 +339,40 @@ const SegmentRow = ({
}
}, [segmentDataVisible, fetchSegment])
return (
<div
className="grid grid-cols-[1fr_20px] gap-x-2 shadow rounded bg-white dark:bg-gray-850 text-gray-700 dark:text-gray-300 text-sm py-3 px-3 transition-all"
onMouseEnter={prefetchSegment}
>
<div className="flex gap-x-2 text-left">
<input
id={String(id)}
type="checkbox"
checked={selected}
value=""
onChange={toggleSelected}
className="my-0.5 w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
<label
htmlFor={String(id)}
className={classNames(
'cursor-pointer break-all',
selected && 'font-extrabold'
)}
>
{name}
</label>
</div>
<button
className="flex w-5 h-5 items-center justify-center"
onClick={toggleSegmentDataVisible}
>
{segmentDataVisible ? (
<ChevronUpIcon className="block w-4 h-4" />
) : (
<ChevronDownIcon className="block w-4 h-4" />
)}
</button>

{segmentDataVisible && (
<div className="col-span-full mt-3">
<>
{true && (
<div className="col-span-full">
{data?.segment_data ? (
<FilterPillsList
className="flex-wrap"
direction="horizontal"
pills={data.segment_data.filters.map((filter) => ({
// className: 'dark:!bg-gray-700',
plainText: plainFilterText(data.segment_data.labels, filter),
children: styledFilterText(data.segment_data.labels, filter),
interactive: false
}))}
/>
<>
<h2 className="font-medium dark:text-gray-100">
Filters in segment
</h2>
<FilterPillsList
className="-mx-1 flex-wrap"
direction="horizontal"
pills={data.segment_data.filters.map((filter) => ({
// className: 'dark:!bg-gray-700',
plainText: plainFilterText(data.segment_data.labels, filter),
children: styledFilterText(data.segment_data.labels, filter),
interactive: false
}))}
/>
<div className="mt-2 text-xs">
{
{
[SegmentType.personal]: 'Personal segment',
[SegmentType.site]: 'Site segment'
}[data.type]
}
</div>

<SegmentAuthorship {...data} className="mt-1 text-xs" />
</>
) : (
'loading'
)}
{!!data && <SegmentAuthorship {...data} className="mt-3 text-xs" />}
{!!data && (
{/* {!!data && } */}
{/* {!!data && (
<div className="col-span-full mt-3 flex gap-x-4 gap-y-2 flex-wrap">
<button
className="flex gap-x-1 text-sm items-center hover:text-indigo-600 fill-current hover:fill-indigo-600"
Expand All @@ -411,18 +394,62 @@ const SegmentRow = ({
Edit
</button>
</div>
)}
)} */}
</div>
)}
</div>
{!!data && (
<div className="mt-4">
<ButtonsRow>
<AppNavigationLink
className={primaryNegativeButtonClass}
path={rootRoute.path}
search={(s) => {
const nonSegmentFilters = query.filters.filter(
(f) => !isSegmentFilter(f)
)
return {
...s,
filters: nonSegmentFilters,
labels: cleanLabels(
nonSegmentFilters,
query.labels,
'segment',
{}
)
}
}}
>
Remove filter
</AppNavigationLink>

<AppNavigationLink
className={primaryNeutralButtonClass}
path={rootRoute.path}
search={(s) => ({
...s,
filters: data.segment_data.filters,
labels: data.segment_data.labels
})}
state={{
expandedSegment: data,
modal: null
}}
>
Edit segment
</AppNavigationLink>
</ButtonsRow>
</div>
)}
</>
)
}

export const AllSegmentsModal = () => {
const { query } = useQueryContext()
const querySegmentIds: number[] =
(query.filters.find(isSegmentFilter)?.[2] as number[]) ?? []
const { data } = useSegmentsListQuery()
const q = useSegmentsListQuery()
const data = q.data?.filter((d) => querySegmentIds.includes(d.id))
const [search, setSearch] = useState<string>()
const [selectedSegmentIds, setSelectedSegmentIds] =
useState<number[]>(querySegmentIds)
Expand Down Expand Up @@ -468,134 +495,40 @@ export const AllSegmentsModal = () => {
setUpToSiteSegment(4)
}, [data, search])

const segment = data ? data[0] : null

return (
<ModalWithRouting
maxWidth="460px"
className="p-6 min-h-fit text-gray-700 dark:text-gray-300"
>
<div className="flex justify-between items-center">
<div className="flex items-center gap-x-2">
<h1 className="text-xl font-bold dark:text-gray-100">Segments</h1>
<h1 className="text-xl font-bold dark:text-gray-100">
{segment ? segment.name : 'Segment'}
</h1>
</div>
<SearchInput onSearch={(v) => setSearch(v)} />
{/* <SearchInput onSearch={(v) => setSearch(v)} /> */}
</div>
<div className="my-4 border-b border-gray-300"></div>

<div className="flex flex-col gap-y-2">
{[
{
segments: personalSegments,
title: 'Personal',
sliceEnd: upToPersonalSegment,
showMore: () => setUpToPersonalSegment((curr) => curr + 10)
},
{
segments: siteSegments,
title: 'Site',
sliceEnd: upToSiteSegment,
showMore: () => setUpToSiteSegment((curr) => curr + 10)
}
]
.filter((i) => !!i.segments?.length)
.map(({ segments, title, sliceEnd, showMore }) => (
<React.Fragment key={title}>
<h2 className="mt-2 text-l font-bold dark:text-gray-100">
{title}
</h2>
{segments!.slice(0, sliceEnd).map((item) => (
<SegmentRow
segmentDataVisible={segmentDataVisibleIds.includes(item.id)}
toggleSegmentDataVisible={getToggleExpanded(item.id)}
key={item.id}
{...item}
toggleSelected={getToggleSelected(item.id)}
selected={selectedSegmentIds.includes(item.id)}
/>
))}
{segments?.length && sliceEnd < segments.length && (
<button
onClick={showMore}
className={classNames(
'self-center mt-1',
secondaryButtonClass
)}
>
Show more
</button>
)}
</React.Fragment>
))}
{!segment
? null
: [segment].map((item) => (
<SegmentRow
segmentDataVisible={segmentDataVisibleIds.includes(item.id)}
toggleSegmentDataVisible={getToggleExpanded(item.id)}
key={item.id}
{...item}
toggleSelected={getToggleSelected(item.id)}
selected={selectedSegmentIds.includes(item.id)}
/>
))}
{!personalSegments?.length && !siteSegments?.length && (
<p>No segments found.</p>
)}
</div>

<div className="mt-4">
<ButtonsRow>
<AppNavigationLink
className={primaryNeutralButtonClass}
path={rootRoute.path}
search={(s) => {
const nonSegmentFilters = query.filters.filter(
(f) => !isSegmentFilter(f)
)
if (!proposedSegmentFilter) {
return {
...s,
filters: nonSegmentFilters,
labels: cleanLabels(
nonSegmentFilters,
query.labels,
'segment',
{}
)
}
}
const filters = nonSegmentFilters.concat([proposedSegmentFilter])
const labels = cleanLabels(
filters,
query.labels,
'segment',
Object.fromEntries(
selectedSegmentIds.map((id) => [
formatSegmentIdAsLabelKey(id),
data?.find((i) => i.id === id)?.name ?? ''
])
)
)
return {
...s,
filters,
labels
}
}}
>
Apply {selectedSegmentIds.length}{' '}
{selectedSegmentIds.length === 1 ? 'segment' : 'segments'}
</AppNavigationLink>
<AppNavigationLink
className={primaryNegativeButtonClass}
path={rootRoute.path}
search={(s) => {
const nonSegmentFilters = query.filters.filter(
(f) => !isSegmentFilter(f)
)
return {
...s,
filters: nonSegmentFilters,
labels: cleanLabels(
nonSegmentFilters,
query.labels,
'segment',
{}
)
}
}}
>
Clear
</AppNavigationLink>
</ButtonsRow>
</div>
</ModalWithRouting>
)
}
Loading
Loading