Merge pull request #454 from SuanmoSuanyangTechnology/fix/memory_web_zy

fix(web): memory use modal replace
This commit is contained in:
yingzhao
2026-03-04 16:30:01 +08:00
committed by GitHub
6 changed files with 84 additions and 14 deletions

View File

@@ -1,12 +1,13 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:31:50
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:31:50
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-04 16:22:03
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { App } from 'antd'
import Empty from '@/components/Empty'
import RbCard from '@/components/RbCard/Card'
@@ -20,6 +21,7 @@ import RbAlert from '@/components/RbAlert'
* @property {Array} suggestions - List of suggestions with actionable steps
*/
interface Suggestions {
exists?: boolean;
health_summary: string;
suggestions: Array<{
type: string;
@@ -35,9 +37,10 @@ interface Suggestions {
* Displays emotional health suggestions with actionable steps
* Shows health summary and prioritized recommendations
*/
const Suggestions = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
const Suggestions = forwardRef<{ handleRefresh: () => void; }, { refresh: () => void; }>(({ refresh }, ref) => {
const { t } = useTranslation()
const { id } = useParams()
const { modal } = App.useApp()
const [loading, setLoading] = useState(false)
const [suggestions, setSuggestions] = useState<Suggestions | null>(null)
@@ -52,7 +55,19 @@ const Suggestions = forwardRef<{ handleRefresh: () => void; }>((_props, ref) =>
setLoading(true)
getEmotionSuggestions(id)
.then((res) => {
setSuggestions(res as Suggestions)
const response = res as Suggestions
if (!response.exists && (!response.suggestions || !response.suggestions?.length)) {
modal.confirm({
title: t('statementDetail.noData'),
okText: t('common.refresh'),
cancelText: t('common.cancel'),
onOk: () => {
refresh()
}
})
} else {
setSuggestions(res as Suggestions)
}
})
.finally(() => {
setLoading(false)

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-01-08 19:46:02
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-04 16:26:55
*/
import { forwardRef, useImperativeHandle, useRef, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { Row, Col, App } from 'antd'
@@ -12,25 +18,40 @@ import {
implicitCheckData,
} from '@/api/memory'
const ImplicitDetail = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
/**
* ImplicitDetail Component - Displays user's implicit memory profile
* Shows unconscious preferences, personality traits, interests and habits
*/
const ImplicitDetail = forwardRef<{ handleRefresh: () => void; }, { refresh: () => void; }>(({
refresh
}, ref) => {
const { t } = useTranslation()
const { id } = useParams()
const { message } = App.useApp()
const { modal } = App.useApp()
const preferencesRef = useRef<{ handleRefresh: () => void; }>(null)
const portraitRef = useRef<{ handleRefresh: () => void; }>(null)
const interestAreasRef = useRef<{ handleRefresh: () => void; }>(null)
const habitsRef = useRef<{ handleRefresh: () => void; }>(null)
// Check if implicit data exists, prompt user to initialize if not
useEffect(() => {
if (!id) return
implicitCheckData(id)
.then(res => {
if (!(res as { exists: boolean }).exists) {
message.warning(t('implicitDetail.noData'))
modal.confirm({
title: t('implicitDetail.noData'),
okText: t('common.refresh'),
cancelText: t('common.cancel'),
onOk: () => {
refresh()
}
})
}
})
}, [id])
// Refresh all implicit memory components by regenerating profile
const handleRefresh = () => {
if (!id) {
return Promise.resolve()

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2025-12-19 16:54:52
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-04 16:28:00
*/
import { forwardRef, useImperativeHandle, useRef } from 'react'
import { Row, Col, Space } from 'antd';
import { useParams } from 'react-router-dom'
@@ -9,9 +15,17 @@ import Suggestions from '../components/Suggestions'
import { generateSuggestions } from '@/api/memory'
const StatementDetail = forwardRef((_props, ref) => {
/**
* StatementDetail - Displays emotional memory analysis for a user
* Shows word cloud, emotion tags, health index, and personalized suggestions
*/
const StatementDetail = forwardRef<{ handleRefresh: () => void },{ refresh: () => void; }>(({
refresh
}, ref) => {
const { id } = useParams()
const suggestionsRef = useRef<{ handleRefresh: () => void; }>(null)
// Regenerate suggestions and refresh the Suggestions child component
const handleRefresh = () => {
if (!id) {
return Promise.resolve()
@@ -41,7 +55,7 @@ const StatementDetail = forwardRef((_props, ref) => {
</Space>
</Col>
<Col span={12}>
<Suggestions ref={suggestionsRef} />
<Suggestions ref={suggestionsRef} refresh={refresh} />
</Col>
</Row>
)

View File

@@ -1,8 +1,13 @@
/*
* @Author: ZhaoYing
* @Date: 2026-01-07 20:37:34
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-04 16:27:14
*/
import { type FC, useEffect, useState, useMemo, useRef } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { Dropdown, Button } from 'antd'
import { LoadingOutlined } from '@ant-design/icons';
import PageHeader from '../components/PageHeader'
import StatementDetail from './StatementDetail'
@@ -19,11 +24,16 @@ import {
import refreshIcon from '@/assets/images/refresh_hover.svg'
import GraphDetail from './GraphDetail'
/**
* Detail page for user memory - renders different memory type views
* based on the `type` route param
*/
const Detail: FC = () => {
const { t } = useTranslation()
const { id, type } = useParams()
const navigate = useNavigate()
const [name, setName] = useState<string>('')
// Refs for child components that support imperative refresh
const forgetDetailRef = useRef<{ handleRefresh: () => void }>(null)
const statementDetailRef = useRef<{ handleRefresh: () => void }>(null)
const implicitDetailRef = useRef<{ handleRefresh: () => void }>(null)
@@ -33,6 +43,7 @@ const Detail: FC = () => {
getData()
}, [id])
// Fetch end user profile to display the user's name in the header
const getData = () => {
if (!id) return
getEndUserProfile(id).then((res) => {
@@ -40,15 +51,21 @@ const Detail: FC = () => {
setName(response.other_name || response.id)
})
}
// Build dropdown menu items for switching between memory types
const items = useMemo(() => {
return ['PERCEPTUAL_MEMORY', 'WORKING_MEMORY', 'EMOTIONAL_MEMORY', 'SHORT_TERM_MEMORY', 'IMPLICIT_MEMORY', 'EPISODIC_MEMORY', 'EXPLICIT_MEMORY', 'FORGET_MEMORY']
.map(key => ({ key, label: t(`userMemory.${key}`) }))
}, [t])
// Navigate to the selected memory type detail page
const onClick = ({ key }: { key: string }) => {
navigate(`/user-memory/detail/${id}/${key}`, { replace: true })
}
const [loading, setLoading] = useState(false)
// Trigger refresh on the active memory type's child component
const handleRefresh = () => {
setLoading(true)
let response: any = null
@@ -64,6 +81,7 @@ const Detail: FC = () => {
break
}
// If the child returns a Promise, wait for it before clearing loading state
if (response instanceof Promise) {
response.finally(() => {
setLoading(false)
@@ -99,9 +117,9 @@ const Detail: FC = () => {
</Button>}
/>
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:py-3 rb:px-4">
{type === 'EMOTIONAL_MEMORY' && <StatementDetail ref={statementDetailRef} />}
{type === 'EMOTIONAL_MEMORY' && <StatementDetail ref={statementDetailRef} refresh={handleRefresh} />}
{type === 'FORGET_MEMORY' && <ForgetDetail ref={forgetDetailRef} />}
{type === 'IMPLICIT_MEMORY' && <ImplicitDetail ref={implicitDetailRef} />}
{type === 'IMPLICIT_MEMORY' && <ImplicitDetail ref={implicitDetailRef} refresh={handleRefresh} />}
{type === 'SHORT_TERM_MEMORY' && <ShortTermDetail />}
{type === 'PERCEPTUAL_MEMORY' && <PerceptualDetail />}
{type === 'EPISODIC_MEMORY' && <EpisodicDetail />}