add "mark as read up to here"

This commit is contained in:
Athou
2022-08-24 09:08:10 +02:00
parent a1fb5871d1
commit 126a5e3bbc
5 changed files with 84 additions and 31 deletions

View File

@@ -13,6 +13,7 @@ import {
LoginRequest,
MarkRequest,
Metrics,
MultipleMarkRequest,
PasswordResetRequest,
ProfileModificationRequest,
RegistrationRequest,
@@ -45,6 +46,7 @@ export const client = {
},
entry: {
mark: (req: MarkRequest) => axiosInstance.post("entry/mark", req),
markMultiple: (req: MultipleMarkRequest) => axiosInstance.post("entry/markMultiple", req),
star: (req: StarRequest) => axiosInstance.post("entry/star", req),
},
feed: {

View File

@@ -79,6 +79,34 @@ export const markEntry = createAsyncThunk(
condition: arg => arg.entry.read !== arg.read,
}
)
export const markMultipleEntries = createAsyncThunk(
"entries/entry/markMultiple",
async (arg: { entries: Entry[]; read: boolean }, thunkApi) => {
const requests: MarkRequest[] = arg.entries.map(e => ({
id: e.id,
read: arg.read,
}))
await client.entry.markMultiple({ requests })
thunkApi.dispatch(reloadTree())
}
)
export const markEntriesUpToEntry = createAsyncThunk<void, Entry, { state: RootState }>(
"entries/entry/upToEntry",
async (arg, thunkApi) => {
const state = thunkApi.getState()
const { entries } = state.entries
const index = entries.findIndex(e => e.id === arg.id)
if (index === -1) return
thunkApi.dispatch(
markMultipleEntries({
entries: entries.slice(0, index + 1),
read: true,
})
)
}
)
export const markAllEntries = createAsyncThunk<void, { sourceType: EntrySourceType; req: MarkRequest }, { state: RootState }>(
"entries/entry/markAll",
async (arg, thunkApi) => {
@@ -159,6 +187,13 @@ export const entriesSlice = createSlice({
e.read = action.meta.arg.read
})
})
builder.addCase(markMultipleEntries.pending, (state, action) => {
state.entries
.filter(e => action.meta.arg.entries.some(e2 => e2.id === e.id))
.forEach(e => {
e.read = action.meta.arg.read
})
})
builder.addCase(markAllEntries.pending, (state, action) => {
state.entries
.filter(e => (action.meta.arg.req.olderThan ? e.date < action.meta.arg.req.olderThan : true))

View File

@@ -1,10 +1,10 @@
import { t } from "@lingui/macro"
import { Checkbox, Group, Popover } from "@mantine/core"
import { markEntry, starEntry } from "app/slices/entries"
import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
import { useAppDispatch, useAppSelector } from "app/store"
import { Entry } from "app/types"
import { ActionButton } from "components/ActionButtton"
import { TbExternalLink, TbShare, TbStar, TbStarOff } from "react-icons/tb"
import { TbArrowBarToDown, TbExternalLink, TbShare, TbStar, TbStarOff } from "react-icons/tb"
import { ShareButtons } from "./ShareButtons"
interface FeedEntryFooterProps {
@@ -21,38 +21,46 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
const readStatusCheckboxClicked = () => dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))
return (
<Group>
{props.entry.markable && (
<Checkbox
label={t`Keep unread`}
checked={!props.entry.read}
onChange={readStatusCheckboxClicked}
styles={{
label: { cursor: "pointer" },
input: { cursor: "pointer" },
}}
<Group position="apart">
<Group>
{props.entry.markable && (
<Checkbox
label={t`Keep unread`}
checked={!props.entry.read}
onChange={readStatusCheckboxClicked}
styles={{
label: { cursor: "pointer" },
input: { cursor: "pointer" },
}}
/>
)}
<ActionButton
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
label={props.entry.starred ? t`Unstar` : t`Star`}
onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}
/>
)}
{showSharingButtons && (
<Popover withArrow withinPortal shadow="md">
<Popover.Target>
<ActionButton icon={<TbShare size={18} />} label={t`Share`} />
</Popover.Target>
<Popover.Dropdown>
<ShareButtons url={props.entry.url} description={props.entry.title} />
</Popover.Dropdown>
</Popover>
)}
<a href={props.entry.url} target="_blank" rel="noreferrer">
<ActionButton icon={<TbExternalLink size={18} />} label={t`Open link`} />
</a>
</Group>
<ActionButton
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
label={props.entry.starred ? t`Unstar` : t`Star`}
onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}
icon={<TbArrowBarToDown size={18} />}
label={t`Mark as read up to here`}
onClick={() => dispatch(markEntriesUpToEntry(props.entry))}
/>
{showSharingButtons && (
<Popover withArrow withinPortal shadow="md">
<Popover.Target>
<ActionButton icon={<TbShare size={18} />} label={t`Share`} />
</Popover.Target>
<Popover.Dropdown>
<ShareButtons url={props.entry.url} description={props.entry.title} />
</Popover.Dropdown>
</Popover>
)}
<a href={props.entry.url} target="_blank" rel="noreferrer">
<ActionButton icon={<TbExternalLink size={18} />} label={t`Open link`} />
</a>
</Group>
)
}

View File

@@ -394,6 +394,10 @@ msgstr "Mark all as read"
msgid "Mark all entries as read"
msgstr "Mark all entries as read"
#: src/components/content/FeedEntryFooter.tsx
msgid "Mark as read up to here"
msgstr "Mark as read up to here"
#: src/components/header/ProfileMenu.tsx
msgid "Metrics"
msgstr "Metrics"

View File

@@ -394,6 +394,10 @@ msgstr "Tout marquer comme lu"
msgid "Mark all entries as read"
msgstr "Marquer toutes les entrées comme lues"
#: src/components/content/FeedEntryFooter.tsx
msgid "Mark as read up to here"
msgstr "Marquer comme lu jusqu'ici"
#: src/components/header/ProfileMenu.tsx
msgid "Metrics"
msgstr "Métriques"