fix listrecord-created-sort
This commit is contained in:
@@ -48,7 +48,7 @@ export default function App() {
|
|||||||
const records = await agent.api.com.atproto.repo.listRecords({
|
const records = await agent.api.com.atproto.repo.listRecords({
|
||||||
repo: user.did,
|
repo: user.did,
|
||||||
collection: 'ai.syui.log.chat',
|
collection: 'ai.syui.log.chat',
|
||||||
limit: 50
|
limit: 100
|
||||||
})
|
})
|
||||||
|
|
||||||
// Group questions and answers together
|
// Group questions and answers together
|
||||||
@@ -83,8 +83,8 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Sort by creation time (newest first)
|
// Sort by creation time (oldest first) - for chronological conversation flow
|
||||||
chatPairs.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
chatPairs.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
|
||||||
|
|
||||||
setUserChatRecords(chatPairs)
|
setUserChatRecords(chatPairs)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -83,14 +83,11 @@ export const atproto = {
|
|||||||
return await request(`${apiEndpoint}/xrpc/${ENDPOINTS.getProfile}?actor=${actor}`)
|
return await request(`${apiEndpoint}/xrpc/${ENDPOINTS.getProfile}?actor=${actor}`)
|
||||||
},
|
},
|
||||||
|
|
||||||
async getRecords(pds, repo, collection, limit = 10, cursor = null, reverse = false) {
|
async getRecords(pds, repo, collection, limit = 10, cursor = null) {
|
||||||
let url = `${pds}/xrpc/${ENDPOINTS.listRecords}?repo=${repo}&collection=${collection}&limit=${limit}`
|
let url = `${pds}/xrpc/${ENDPOINTS.listRecords}?repo=${repo}&collection=${collection}&limit=${limit}`
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
url += `&cursor=${cursor}`
|
url += `&cursor=${cursor}`
|
||||||
}
|
}
|
||||||
if (reverse) {
|
|
||||||
url += `&reverse=true`
|
|
||||||
}
|
|
||||||
const res = await request(url)
|
const res = await request(url)
|
||||||
return {
|
return {
|
||||||
records: res.records || [],
|
records: res.records || [],
|
||||||
@@ -118,6 +115,48 @@ export const atproto = {
|
|||||||
|
|
||||||
// Use Agent's putRecord method instead of direct fetch
|
// Use Agent's putRecord method instead of direct fetch
|
||||||
return await agent.com.atproto.repo.putRecord(record)
|
return await agent.com.atproto.repo.putRecord(record)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Find all records for a specific post by paginating through all records
|
||||||
|
async findRecordsForPost(pds, repo, collection, targetRkey) {
|
||||||
|
let cursor = null
|
||||||
|
let allMatchingRecords = []
|
||||||
|
let pageCount = 0
|
||||||
|
const maxPages = 50 // Safety limit to prevent infinite loops
|
||||||
|
|
||||||
|
do {
|
||||||
|
pageCount++
|
||||||
|
if (pageCount > maxPages) {
|
||||||
|
console.warn(`Reached max pages (${maxPages}) while searching for ${targetRkey}`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await this.getRecords(pds, repo, collection, 100, cursor)
|
||||||
|
|
||||||
|
// Filter records that match the target post
|
||||||
|
const matchingRecords = result.records.filter(record => {
|
||||||
|
const postUrl = record.value?.post?.url
|
||||||
|
if (!postUrl) return false
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Extract rkey from URL
|
||||||
|
const recordRkey = new URL(postUrl).pathname.split('/').pop()?.replace(/\.html$/, '')
|
||||||
|
return recordRkey === targetRkey
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
allMatchingRecords.push(...matchingRecords)
|
||||||
|
cursor = result.cursor
|
||||||
|
|
||||||
|
// Optional: Stop early if we found some records (uncomment if desired)
|
||||||
|
// if (allMatchingRecords.length > 0) break
|
||||||
|
|
||||||
|
} while (cursor)
|
||||||
|
|
||||||
|
console.log(`Found ${allMatchingRecords.length} records for ${targetRkey} after searching ${pageCount} pages`)
|
||||||
|
return allMatchingRecords
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +193,7 @@ export const collections = {
|
|||||||
const cached = dataCache.get(cacheKey)
|
const cached = dataCache.get(cacheKey)
|
||||||
if (cached) return cached
|
if (cached) return cached
|
||||||
|
|
||||||
const data = await atproto.getRecords(pds, repo, `${collection}.chat.comment`, limit, null, true) // reverse=true for chronological order
|
const data = await atproto.getRecords(pds, repo, `${collection}.chat.comment`, limit)
|
||||||
// Extract records array for backward compatibility
|
// Extract records array for backward compatibility
|
||||||
const records = data.records || data
|
const records = data.records || data
|
||||||
dataCache.set(cacheKey, records)
|
dataCache.set(cacheKey, records)
|
||||||
@@ -164,7 +203,7 @@ export const collections = {
|
|||||||
async getChat(pds, repo, collection, limit = 10, cursor = null) {
|
async getChat(pds, repo, collection, limit = 10, cursor = null) {
|
||||||
// Don't use cache for pagination requests
|
// Don't use cache for pagination requests
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
const result = await atproto.getRecords(pds, repo, `${collection}.chat`, limit, cursor, true) // reverse=true for chronological order
|
const result = await atproto.getRecords(pds, repo, `${collection}.chat`, limit, cursor)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +214,7 @@ export const collections = {
|
|||||||
return Array.isArray(cached) ? { records: cached, cursor: null } : cached
|
return Array.isArray(cached) ? { records: cached, cursor: null } : cached
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await atproto.getRecords(pds, repo, `${collection}.chat`, limit, null, true) // reverse=true for chronological order
|
const data = await atproto.getRecords(pds, repo, `${collection}.chat`, limit)
|
||||||
// Cache only the records array for backward compatibility
|
// Cache only the records array for backward compatibility
|
||||||
dataCache.set(cacheKey, data.records || data)
|
dataCache.set(cacheKey, data.records || data)
|
||||||
return data
|
return data
|
||||||
@@ -217,6 +256,53 @@ export const collections = {
|
|||||||
return records
|
return records
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Find chat records for a specific post using pagination
|
||||||
|
async getChatForPost(pds, repo, collection, targetRkey) {
|
||||||
|
const cacheKey = dataCache.generateKey('chatForPost', pds, repo, collection, targetRkey)
|
||||||
|
const cached = dataCache.get(cacheKey)
|
||||||
|
if (cached) return cached
|
||||||
|
|
||||||
|
const records = await atproto.findRecordsForPost(pds, repo, `${collection}.chat`, targetRkey)
|
||||||
|
|
||||||
|
// Process into chat pairs like the original getChat function
|
||||||
|
const chatPairs = []
|
||||||
|
const recordMap = new Map()
|
||||||
|
|
||||||
|
// First pass: organize records by base rkey
|
||||||
|
records.forEach(record => {
|
||||||
|
const rkey = record.uri.split('/').pop()
|
||||||
|
const baseRkey = rkey.replace('-answer', '')
|
||||||
|
|
||||||
|
if (!recordMap.has(baseRkey)) {
|
||||||
|
recordMap.set(baseRkey, { question: null, answer: null })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.value.type === 'question') {
|
||||||
|
recordMap.get(baseRkey).question = record
|
||||||
|
} else if (record.value.type === 'answer') {
|
||||||
|
recordMap.get(baseRkey).answer = record
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Second pass: create chat pairs
|
||||||
|
recordMap.forEach((pair, rkey) => {
|
||||||
|
if (pair.question) {
|
||||||
|
chatPairs.push({
|
||||||
|
rkey,
|
||||||
|
question: pair.question,
|
||||||
|
answer: pair.answer,
|
||||||
|
createdAt: pair.question.value.createdAt
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Sort by creation time (oldest first) - for chronological conversation flow
|
||||||
|
chatPairs.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
|
||||||
|
|
||||||
|
dataCache.set(cacheKey, chatPairs)
|
||||||
|
return chatPairs
|
||||||
|
},
|
||||||
|
|
||||||
// 投稿後にキャッシュを無効化
|
// 投稿後にキャッシュを無効化
|
||||||
invalidateCache(collection) {
|
invalidateCache(collection) {
|
||||||
dataCache.invalidatePattern(collection)
|
dataCache.invalidatePattern(collection)
|
||||||
|
@@ -24,6 +24,24 @@ function getCorrectWebUrl(avatarUrl) {
|
|||||||
|
|
||||||
export default function ChatRecordList({ chatPairs, chatHasMore, onLoadMoreChat, apiConfig, user = null, agent = null, onRecordDeleted = null }) {
|
export default function ChatRecordList({ chatPairs, chatHasMore, onLoadMoreChat, apiConfig, user = null, agent = null, onRecordDeleted = null }) {
|
||||||
const [expandedRecords, setExpandedRecords] = useState(new Set())
|
const [expandedRecords, setExpandedRecords] = useState(new Set())
|
||||||
|
|
||||||
|
// Sort chat pairs by creation time (oldest first) for chronological conversation flow
|
||||||
|
const sortedChatPairs = Array.isArray(chatPairs)
|
||||||
|
? [...chatPairs].sort((a, b) => {
|
||||||
|
const dateA = new Date(a.createdAt)
|
||||||
|
const dateB = new Date(b.createdAt)
|
||||||
|
|
||||||
|
// If creation times are the same, sort by URI (which contains sequence info)
|
||||||
|
if (dateA.getTime() === dateB.getTime()) {
|
||||||
|
const uriA = a.question?.uri || ''
|
||||||
|
const uriB = b.question?.uri || ''
|
||||||
|
return uriA.localeCompare(uriB)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateA - dateB
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
|
||||||
|
|
||||||
const toggleJsonView = (key) => {
|
const toggleJsonView = (key) => {
|
||||||
const newExpanded = new Set(expandedRecords)
|
const newExpanded = new Set(expandedRecords)
|
||||||
@@ -35,7 +53,7 @@ export default function ChatRecordList({ chatPairs, chatHasMore, onLoadMoreChat,
|
|||||||
setExpandedRecords(newExpanded)
|
setExpandedRecords(newExpanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chatPairs || chatPairs.length === 0) {
|
if (!sortedChatPairs || sortedChatPairs.length === 0) {
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<p>チャット履歴がありません</p>
|
<p>チャット履歴がありません</p>
|
||||||
@@ -84,7 +102,7 @@ export default function ChatRecordList({ chatPairs, chatHasMore, onLoadMoreChat,
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
{chatPairs.map((chatPair, i) => (
|
{sortedChatPairs.map((chatPair, i) => (
|
||||||
<div key={chatPair.rkey} className="chat-conversation">
|
<div key={chatPair.rkey} className="chat-conversation">
|
||||||
{/* Question */}
|
{/* Question */}
|
||||||
{chatPair.question && (
|
{chatPair.question && (
|
||||||
|
@@ -4,8 +4,17 @@ import ChatRecordList from './ChatRecordList.jsx'
|
|||||||
import ProfileRecordList from './ProfileRecordList.jsx'
|
import ProfileRecordList from './ProfileRecordList.jsx'
|
||||||
import LoadingSkeleton from './LoadingSkeleton.jsx'
|
import LoadingSkeleton from './LoadingSkeleton.jsx'
|
||||||
import { logger } from '../utils/logger.js'
|
import { logger } from '../utils/logger.js'
|
||||||
|
import { collections } from '../api/atproto.js'
|
||||||
|
import { getApiConfig } from '../utils/pds.js'
|
||||||
|
import { env } from '../config/env.js'
|
||||||
|
|
||||||
export default function RecordTabs({ langRecords, commentRecords, userComments, chatRecords, chatHasMore, onLoadMoreChat, userChatRecords, userChatLoading, baseRecords, apiConfig, pageContext, user = null, agent = null, onRecordDeleted = null }) {
|
export default function RecordTabs({ langRecords, commentRecords, userComments, chatRecords, chatHasMore, onLoadMoreChat, userChatRecords, userChatLoading, baseRecords, apiConfig, pageContext, user = null, agent = null, onRecordDeleted = null }) {
|
||||||
|
// State for page-specific chat records
|
||||||
|
const [pageSpecificChatRecords, setPageSpecificChatRecords] = useState([])
|
||||||
|
const [pageSpecificLoading, setPageSpecificLoading] = useState(false)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check if current page has matching chat records (AI posts always have chat records)
|
// Check if current page has matching chat records (AI posts always have chat records)
|
||||||
const isAiPost = !pageContext.isTopPage && Array.isArray(chatRecords) && chatRecords.some(chatPair => {
|
const isAiPost = !pageContext.isTopPage && Array.isArray(chatRecords) && chatRecords.some(chatPair => {
|
||||||
const recordUrl = chatPair.question?.value?.post?.url
|
const recordUrl = chatPair.question?.value?.post?.url
|
||||||
@@ -20,59 +29,68 @@ export default function RecordTabs({ langRecords, commentRecords, userComments,
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState(isAiPost ? 'collection' : 'profiles')
|
const [activeTab, setActiveTab] = useState(isAiPost ? 'collection' : 'profiles')
|
||||||
|
|
||||||
// Monitor activeTab changes
|
// Fixed useEffect with proper dependency array
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
logger.log('RecordTabs: activeTab changed to', activeTab)
|
if (!pageContext.isTopPage && pageContext.rkey) {
|
||||||
}, [activeTab])
|
|
||||||
|
const fetchPageSpecificChats = async () => {
|
||||||
|
setPageSpecificLoading(true)
|
||||||
|
try {
|
||||||
|
const apiConfig = getApiConfig(`https://${env.pds}`)
|
||||||
|
const { atproto } = await import('../api/atproto.js')
|
||||||
|
const did = await atproto.getDid(env.pds, env.admin)
|
||||||
|
|
||||||
|
const records = await collections.getChatForPost(
|
||||||
|
apiConfig.pds,
|
||||||
|
did,
|
||||||
|
env.collection,
|
||||||
|
pageContext.rkey
|
||||||
|
)
|
||||||
|
setPageSpecificChatRecords(records)
|
||||||
|
} catch (error) {
|
||||||
|
setPageSpecificChatRecords([])
|
||||||
|
} finally {
|
||||||
|
setPageSpecificLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchPageSpecificChats()
|
||||||
|
} else {
|
||||||
|
setPageSpecificChatRecords([])
|
||||||
|
}
|
||||||
|
}, [pageContext.isTopPage, pageContext.rkey]) // Add proper dependencies
|
||||||
|
|
||||||
logger.log('RecordTabs: activeTab is', activeTab)
|
|
||||||
logger.log('RecordTabs: commentRecords prop:', commentRecords?.length || 0, commentRecords)
|
|
||||||
|
|
||||||
// Filter records based on page context
|
// Filter records based on page context
|
||||||
const filterRecords = (records, isProfile = false) => {
|
const filterRecords = (records, isProfile = false) => {
|
||||||
// Ensure records is an array
|
// Ensure records is an array
|
||||||
const recordsArray = Array.isArray(records) ? records : []
|
const recordsArray = Array.isArray(records) ? records : []
|
||||||
|
|
||||||
logger.log('filterRecords called with:', {
|
|
||||||
recordsLength: recordsArray.length,
|
|
||||||
isProfile,
|
|
||||||
isTopPage: pageContext.isTopPage,
|
|
||||||
pageRkey: pageContext.rkey,
|
|
||||||
records: recordsArray
|
|
||||||
})
|
|
||||||
|
|
||||||
if (pageContext.isTopPage) {
|
if (pageContext.isTopPage) {
|
||||||
// Top page: show latest 3 records
|
// Top page: show latest 3 records
|
||||||
const result = recordsArray.slice(0, 3)
|
return recordsArray.slice(0, 3)
|
||||||
logger.log('filterRecords: Top page result:', result.length, result)
|
|
||||||
return result
|
|
||||||
} else {
|
} else {
|
||||||
// Individual page: show records matching the URL
|
// Individual page: show records matching the URL
|
||||||
const filtered = recordsArray.filter(record => {
|
const filtered = recordsArray.filter(record => {
|
||||||
// Profile records should always be shown
|
// Profile records should always be shown
|
||||||
if (isProfile || record.value?.type === 'profile') {
|
if (isProfile || record.value?.type === 'profile') {
|
||||||
logger.log('filterRecords: Profile record included:', record.value?.type)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const recordUrl = record.value?.post?.url
|
const recordUrl = record.value?.post?.url
|
||||||
if (!recordUrl) {
|
if (!recordUrl) {
|
||||||
logger.log('filterRecords: No recordUrl found for record:', record.value?.type)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const recordRkey = new URL(recordUrl).pathname.split('/').pop()?.replace(/\.html$/, '')
|
const recordRkey = new URL(recordUrl).pathname.split('/').pop()?.replace(/\.html$/, '')
|
||||||
const matches = recordRkey === pageContext.rkey
|
return recordRkey === pageContext.rkey
|
||||||
logger.log('filterRecords: URL matching:', { recordRkey, pageRkey: pageContext.rkey, matches })
|
|
||||||
return matches
|
|
||||||
} catch {
|
} catch {
|
||||||
logger.log('filterRecords: URL parsing failed for:', recordUrl)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
logger.log('filterRecords: Individual page result:', filtered.length, filtered)
|
|
||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,25 +100,15 @@ export default function RecordTabs({ langRecords, commentRecords, userComments,
|
|||||||
// Ensure chatPairs is an array
|
// Ensure chatPairs is an array
|
||||||
const chatArray = Array.isArray(chatPairs) ? chatPairs : []
|
const chatArray = Array.isArray(chatPairs) ? chatPairs : []
|
||||||
|
|
||||||
logger.log('filterChatRecords called:', {
|
|
||||||
isTopPage: pageContext.isTopPage,
|
|
||||||
rkey: pageContext.rkey,
|
|
||||||
chatPairsLength: chatArray.length,
|
|
||||||
chatPairsType: typeof chatPairs,
|
|
||||||
isArray: Array.isArray(chatPairs)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (pageContext.isTopPage) {
|
if (pageContext.isTopPage) {
|
||||||
// Top page: show latest 3 pairs
|
// Top page: show latest 3 pairs
|
||||||
const result = chatArray.slice(0, 3)
|
return chatArray.slice(0, 3)
|
||||||
logger.log('Top page: returning', result.length, 'pairs')
|
|
||||||
return result
|
|
||||||
} else {
|
} else {
|
||||||
// Individual page: show pairs matching the URL (compare path only, ignore domain)
|
// Individual page: show pairs matching the URL (compare path only, ignore domain)
|
||||||
const filtered = chatArray.filter(chatPair => {
|
const filtered = chatArray.filter(chatPair => {
|
||||||
const recordUrl = chatPair.question?.value?.post?.url
|
const recordUrl = chatPair.question?.value?.post?.url
|
||||||
if (!recordUrl) {
|
if (!recordUrl) {
|
||||||
logger.log('No recordUrl for chatPair:', chatPair)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,43 +117,25 @@ export default function RecordTabs({ langRecords, commentRecords, userComments,
|
|||||||
const recordPath = new URL(recordUrl).pathname
|
const recordPath = new URL(recordUrl).pathname
|
||||||
const recordRkey = recordPath.split('/').pop()?.replace(/\.html$/, '')
|
const recordRkey = recordPath.split('/').pop()?.replace(/\.html$/, '')
|
||||||
|
|
||||||
logger.log('Comparing:', { recordRkey, pageRkey: pageContext.rkey, recordUrl })
|
|
||||||
|
|
||||||
// Compare with current page rkey
|
// Compare with current page rkey
|
||||||
const matches = recordRkey === pageContext.rkey
|
return recordRkey === pageContext.rkey
|
||||||
if (matches) {
|
|
||||||
logger.log('Found matching chat pair!')
|
|
||||||
}
|
|
||||||
return matches
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log('Error processing recordUrl:', recordUrl, error)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.log('Individual page: returning', filtered.length, 'filtered pairs')
|
|
||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredLangRecords = filterRecords(Array.isArray(langRecords) ? langRecords : [])
|
const filteredLangRecords = filterRecords(Array.isArray(langRecords) ? langRecords : [])
|
||||||
|
|
||||||
logger.log('RecordTabs: About to filter commentRecords:', commentRecords?.length || 0, commentRecords)
|
|
||||||
const filteredCommentRecords = filterRecords(Array.isArray(commentRecords) ? commentRecords : [])
|
const filteredCommentRecords = filterRecords(Array.isArray(commentRecords) ? commentRecords : [])
|
||||||
logger.log('RecordTabs: After filtering commentRecords:', filteredCommentRecords.length, filteredCommentRecords)
|
|
||||||
|
|
||||||
const filteredUserComments = filterRecords(Array.isArray(userComments) ? userComments : [])
|
const filteredUserComments = filterRecords(Array.isArray(userComments) ? userComments : [])
|
||||||
const filteredChatRecords = filterChatRecords(Array.isArray(chatRecords) ? chatRecords : [])
|
const filteredChatRecords = filterChatRecords(Array.isArray(chatRecords) ? chatRecords : [])
|
||||||
const filteredBaseRecords = filterRecords(Array.isArray(baseRecords) ? baseRecords : [])
|
const filteredBaseRecords = filterRecords(Array.isArray(baseRecords) ? baseRecords : [])
|
||||||
|
|
||||||
logger.log('RecordTabs: filtered results:')
|
|
||||||
logger.log(' - filteredCommentRecords:', filteredCommentRecords.length, filteredCommentRecords)
|
|
||||||
logger.log(' - filteredLangRecords:', filteredLangRecords.length)
|
|
||||||
logger.log(' - filteredUserComments:', filteredUserComments.length)
|
|
||||||
logger.log(' - pageContext:', pageContext)
|
|
||||||
logger.log('RecordTabs: TAB RENDER VALUES:')
|
|
||||||
logger.log(' - filteredCommentRecords.length for tab:', filteredCommentRecords.length)
|
|
||||||
logger.log(' - commentRecords input:', commentRecords?.length || 0)
|
|
||||||
|
|
||||||
// Filter profile records from baseRecords
|
// Filter profile records from baseRecords
|
||||||
const profileRecords = (Array.isArray(baseRecords) ? baseRecords : []).filter(record => record.value?.type === 'profile')
|
const profileRecords = (Array.isArray(baseRecords) ? baseRecords : []).filter(record => record.value?.type === 'profile')
|
||||||
@@ -162,10 +152,7 @@ export default function RecordTabs({ langRecords, commentRecords, userComments,
|
|||||||
<div className="tab-header">
|
<div className="tab-header">
|
||||||
<button
|
<button
|
||||||
className={`tab-btn ${activeTab === 'profiles' ? 'active' : ''}`}
|
className={`tab-btn ${activeTab === 'profiles' ? 'active' : ''}`}
|
||||||
onClick={() => {
|
onClick={() => setActiveTab('profiles')}
|
||||||
logger.log('RecordTabs: Profiles tab clicked')
|
|
||||||
setActiveTab('profiles')
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
about ({filteredProfileRecords.length})
|
about ({filteredProfileRecords.length})
|
||||||
</button>
|
</button>
|
||||||
@@ -177,15 +164,9 @@ export default function RecordTabs({ langRecords, commentRecords, userComments,
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`tab-btn ${activeTab === 'comment' ? 'active' : ''}`}
|
className={`tab-btn ${activeTab === 'comment' ? 'active' : ''}`}
|
||||||
onClick={() => {
|
onClick={() => setActiveTab('comment')}
|
||||||
logger.log('RecordTabs: feedback tab clicked, setting activeTab to comment')
|
|
||||||
setActiveTab('comment')
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
feedback ({(() => {
|
feedback ({filteredCommentRecords.length})
|
||||||
logger.log('RecordTabs: feedback tab render - filteredCommentRecords.length:', filteredCommentRecords.length)
|
|
||||||
return filteredCommentRecords.length
|
|
||||||
})()})
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`tab-btn ${activeTab === 'users' ? 'active' : ''}`}
|
className={`tab-btn ${activeTab === 'users' ? 'active' : ''}`}
|
||||||
@@ -234,19 +215,33 @@ export default function RecordTabs({ langRecords, commentRecords, userComments,
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{activeTab === 'collection' && (
|
{activeTab === 'collection' && (
|
||||||
userChatLoading ? (
|
(userChatLoading || pageSpecificLoading) ? (
|
||||||
<LoadingSkeleton count={2} showTitle={true} />
|
<LoadingSkeleton count={2} showTitle={true} />
|
||||||
) : (
|
) : (() => {
|
||||||
<ChatRecordList
|
const chatPairsToUse = !pageContext.isTopPage && pageSpecificChatRecords.length > 0
|
||||||
chatPairs={filteredChatRecords.length > 0 ? filteredChatRecords : (Array.isArray(userChatRecords) ? userChatRecords : [])}
|
? pageSpecificChatRecords
|
||||||
chatHasMore={filteredChatRecords.length > 0 ? chatHasMore : false}
|
: (filteredChatRecords.length > 0 ? filteredChatRecords : (Array.isArray(userChatRecords) ? userChatRecords : []))
|
||||||
onLoadMoreChat={filteredChatRecords.length > 0 ? onLoadMoreChat : null}
|
|
||||||
apiConfig={apiConfig}
|
return (
|
||||||
user={user}
|
<ChatRecordList
|
||||||
agent={agent}
|
chatPairs={chatPairsToUse}
|
||||||
onRecordDeleted={onRecordDeleted}
|
chatHasMore={
|
||||||
/>
|
!pageContext.isTopPage && pageSpecificChatRecords.length > 0
|
||||||
)
|
? false // Page-specific records don't use pagination
|
||||||
|
: (filteredChatRecords.length > 0 ? chatHasMore : false)
|
||||||
|
}
|
||||||
|
onLoadMoreChat={
|
||||||
|
!pageContext.isTopPage && pageSpecificChatRecords.length > 0
|
||||||
|
? null // Page-specific records don't use pagination
|
||||||
|
: (filteredChatRecords.length > 0 ? onLoadMoreChat : null)
|
||||||
|
}
|
||||||
|
apiConfig={apiConfig}
|
||||||
|
user={user}
|
||||||
|
agent={agent}
|
||||||
|
onRecordDeleted={onRecordDeleted}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})()
|
||||||
)}
|
)}
|
||||||
{activeTab === 'users' && !isAiPost && (
|
{activeTab === 'users' && !isAiPost && (
|
||||||
!userComments ? (
|
!userComments ? (
|
||||||
|
@@ -48,7 +48,7 @@ export function useAdminData() {
|
|||||||
logger.error('getComment error:', err)
|
logger.error('getComment error:', err)
|
||||||
throw err
|
throw err
|
||||||
}),
|
}),
|
||||||
collections.getChat(apiConfig.pds, did, env.collection, 10).catch(err => {
|
collections.getChat(apiConfig.pds, did, env.collection, 100).catch(err => {
|
||||||
logger.error('getChat error:', err)
|
logger.error('getChat error:', err)
|
||||||
throw err
|
throw err
|
||||||
})
|
})
|
||||||
@@ -98,8 +98,12 @@ export function useAdminData() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Sort by creation time (newest first)
|
// Sort by creation time (oldest first) - for chronological conversation flow
|
||||||
chatPairs.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
chatPairs.sort((a, b) => {
|
||||||
|
const dateA = new Date(a.createdAt)
|
||||||
|
const dateB = new Date(b.createdAt)
|
||||||
|
return dateA - dateB
|
||||||
|
})
|
||||||
|
|
||||||
logger.log('useAdminData: raw chat records:', chat.length)
|
logger.log('useAdminData: raw chat records:', chat.length)
|
||||||
logger.log('useAdminData: processed chat pairs:', chatPairs.length, chatPairs)
|
logger.log('useAdminData: processed chat pairs:', chatPairs.length, chatPairs)
|
||||||
@@ -128,7 +132,7 @@ export function useAdminData() {
|
|||||||
try {
|
try {
|
||||||
const apiConfig = getApiConfig(`https://${env.pds}`)
|
const apiConfig = getApiConfig(`https://${env.pds}`)
|
||||||
const did = await atproto.getDid(env.pds, env.admin)
|
const did = await atproto.getDid(env.pds, env.admin)
|
||||||
const chatResult = await collections.getChat(apiConfig.pds, did, env.collection, 10, chatCursor)
|
const chatResult = await collections.getChat(apiConfig.pds, did, env.collection, 100, chatCursor)
|
||||||
|
|
||||||
const newChatRecords = chatResult.records || chatResult
|
const newChatRecords = chatResult.records || chatResult
|
||||||
const newCursor = chatResult.cursor || null
|
const newCursor = chatResult.cursor || null
|
||||||
@@ -168,8 +172,8 @@ export function useAdminData() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Sort new pairs by creation time (newest first)
|
// Sort new pairs by creation time (oldest first) - for chronological conversation flow
|
||||||
newChatPairs.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
newChatPairs.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
|
||||||
|
|
||||||
// Append to existing chat records
|
// Append to existing chat records
|
||||||
setChatRecords(prev => [...prev, ...newChatPairs])
|
setChatRecords(prev => [...prev, ...newChatPairs])
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
|
|
||||||
export function usePageContext() {
|
export function usePageContext() {
|
||||||
const [pageContext, setPageContext] = useState({
|
const [pageContext, setPageContext] = useState({
|
||||||
|
@@ -1875,7 +1875,7 @@ async fn check_and_process_new_posts(
|
|||||||
|
|
||||||
async fn get_existing_records(config: &AuthConfig, collection: &str) -> Result<Vec<serde_json::Value>> {
|
async fn get_existing_records(config: &AuthConfig, collection: &str) -> Result<Vec<serde_json::Value>> {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let url = format!("{}/xrpc/com.atproto.repo.listRecords?repo={}&collection={}&limit=100&reverse=true",
|
let url = format!("{}/xrpc/com.atproto.repo.listRecords?repo={}&collection={}&limit=100",
|
||||||
config.admin.pds,
|
config.admin.pds,
|
||||||
urlencoding::encode(&config.admin.did),
|
urlencoding::encode(&config.admin.did),
|
||||||
urlencoding::encode(collection));
|
urlencoding::encode(collection));
|
||||||
|
Reference in New Issue
Block a user