this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 189 lines 5.2 kB view raw
1import { Trans, useLingui } from '@lingui/react/macro'; 2import { useMemo, useRef, useState } from 'preact/hooks'; 3import { useSearchParams } from 'react-router-dom'; 4 5import Link from '../components/link'; 6import Timeline from '../components/timeline'; 7import { api } from '../utils/api'; 8import { fixNotifications } from '../utils/group-notifications'; 9import { saveStatus } from '../utils/states'; 10import useTitle from '../utils/useTitle'; 11 12const LIMIT = 20; 13const emptySearchParams = new URLSearchParams(); 14 15function Mentions({ columnMode, ...props }) { 16 const { t } = useLingui(); 17 const { masto, instance } = api(); 18 const [searchParams] = columnMode ? [emptySearchParams] : useSearchParams(); 19 const [stateType, setStateType] = useState(null); 20 const type = props?.type || searchParams.get('type') || stateType; 21 useTitle(type === 'private' ? t`Private mentions` : t`Mentions`, '/mentions'); 22 23 const mentionsIterator = useRef(); 24 const latestItem = useRef(); 25 26 async function fetchMentions(firstLoad) { 27 if (firstLoad || !mentionsIterator.current) { 28 mentionsIterator.current = masto.v1.notifications 29 .list({ 30 limit: LIMIT, 31 types: ['mention'], 32 }) 33 .values(); 34 } 35 const results = await mentionsIterator.current.next(); 36 let { value } = results; 37 if (value?.length) { 38 value = fixNotifications(value); 39 40 if (firstLoad) { 41 latestItem.current = value[0].id; 42 console.log('First load', latestItem.current); 43 } 44 45 value.forEach(({ status: item }) => { 46 saveStatus(item, instance); 47 }); 48 } 49 return { 50 ...results, 51 value: value?.map((item) => item.status), 52 }; 53 } 54 55 const conversationsIterator = useRef(); 56 const latestConversationItem = useRef(); 57 async function fetchConversations(firstLoad) { 58 if (firstLoad || !conversationsIterator.current) { 59 conversationsIterator.current = masto.v1.conversations 60 .list({ 61 limit: LIMIT, 62 }) 63 .values(); 64 } 65 const results = await conversationsIterator.current.next(); 66 let { value } = results; 67 value = value?.filter((item) => item.lastStatus); 68 if (value?.length) { 69 if (firstLoad) { 70 latestConversationItem.current = value[0].lastStatus.id; 71 console.log('First load', latestConversationItem.current); 72 } 73 74 value.forEach(({ lastStatus: item }) => { 75 saveStatus(item, instance); 76 }); 77 } 78 console.log('results', results); 79 return { 80 ...results, 81 value: value?.map((item) => item.lastStatus), 82 }; 83 } 84 85 function fetchItems(...args) { 86 if (type === 'private') { 87 return fetchConversations(...args); 88 } 89 return fetchMentions(...args); 90 } 91 92 async function checkForUpdates() { 93 if (type === 'private') { 94 try { 95 const results = await masto.v1.conversations 96 .list({ 97 limit: 1, 98 since_id: latestConversationItem.current, 99 }) 100 .values() 101 .next(); 102 let { value } = results; 103 console.log( 104 'checkForUpdates PRIVATE', 105 latestConversationItem.current, 106 value, 107 ); 108 const valueContainsLatestItem = 109 value[0]?.id === latestConversationItem.current; // since_id might not be supported 110 if (value?.length && !valueContainsLatestItem) { 111 latestConversationItem.current = value[0].lastStatus.id; 112 return true; 113 } 114 return false; 115 } catch (e) { 116 return false; 117 } 118 } else { 119 try { 120 const results = await masto.v1.notifications 121 .list({ 122 limit: 1, 123 types: ['mention'], 124 since_id: latestItem.current, 125 }) 126 .values() 127 .next(); 128 let { value } = results; 129 console.log('checkForUpdates ALL', latestItem.current, value); 130 if (value?.length) { 131 latestItem.current = value[0].id; 132 return true; 133 } 134 return false; 135 } catch (e) { 136 return false; 137 } 138 } 139 } 140 141 const TimelineStart = useMemo(() => { 142 return ( 143 <div class="filter-bar centered"> 144 <Link 145 to="/mentions" 146 class={!type ? 'is-active' : ''} 147 onClick={(e) => { 148 if (columnMode) { 149 e.preventDefault(); 150 setStateType(null); 151 } 152 }} 153 > 154 <Trans>All</Trans> 155 </Link> 156 <Link 157 to="/mentions?type=private" 158 class={type === 'private' ? 'is-active' : ''} 159 onClick={(e) => { 160 if (columnMode) { 161 e.preventDefault(); 162 setStateType('private'); 163 } 164 }} 165 > 166 <Trans>Private</Trans> 167 </Link> 168 </div> 169 ); 170 }, [type]); 171 172 return ( 173 <Timeline 174 title={t`Mentions`} 175 id="mentions" 176 emptyText={t`No one mentioned you :(`} 177 errorText={t`Unable to load mentions.`} 178 instance={instance} 179 fetchItems={fetchItems} 180 checkForUpdates={checkForUpdates} 181 useItemID 182 timelineStart={TimelineStart} 183 refresh={type} 184 filterContext="notifications" 185 /> 186 ); 187} 188 189export default Mentions;