[dev]update search

This commit is contained in:
susie-laptop 2025-03-22 22:53:37 -04:00
parent 167b06315d
commit fbfff98123
12 changed files with 144 additions and 184 deletions

View File

@ -47,32 +47,23 @@ const SearchBar = ({
}; };
}, []); }, []);
// //
const handleFocus = () => { useEffect(() => {
if (searchKeyword.trim().length > 0) { if (isSearching && searchResults.length > 0) {
setShowDropdown(true); setShowDropdown(true);
} }
}; }, [isSearching, searchResults]);
// //
const handleInputChange = (e) => { const handleInputChange = (e) => {
const value = e.target.value;
onSearchChange(e); onSearchChange(e);
if (value.trim().length > 0) {
setShowDropdown(true);
} else {
setShowDropdown(false);
}
}; };
// //
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
onSearch(e); onSearch(e);
if (searchKeyword.trim().length > 0) { // (searchResults)
setShowDropdown(true);
}
}; };
return ( return (
@ -86,7 +77,6 @@ const SearchBar = ({
placeholder={placeholder} placeholder={placeholder}
value={searchKeyword} value={searchKeyword}
onChange={handleInputChange} onChange={handleInputChange}
onFocus={handleFocus}
/> />
{searchKeyword.trim() && ( {searchKeyword.trim() && (
<button <button
@ -107,9 +97,9 @@ const SearchBar = ({
</div> </div>
</form> </form>
{/* 搜索结果下拉框 */} {/* 搜索结果下拉框 - 仅在用户搜索且有结果时显示 */}
{showDropdown && ( {showDropdown && (isSearchLoading || searchResults?.length > 0) && (
<div className='position-absolute bg-white shadow-sm rounded-3 mt-1 w-100 search-results-dropdown'> <div className='position-absolute bg-white shadow-sm rounded-3 mt-1 w-100 search-results-dropdown z-1'>
<div className='p-2 overflow-auto' style={{ maxHeight: '350px', zIndex: '1050' }}> <div className='p-2 overflow-auto' style={{ maxHeight: '350px', zIndex: '1050' }}>
{isSearchLoading ? ( {isSearchLoading ? (
<div className='text-center p-3'> <div className='text-center p-3'>

View File

@ -11,7 +11,7 @@ const Snackbar = ({ type = 'primary', message, duration = 3000, onClose }) => {
}, duration); }, duration);
return () => clearTimeout(timer); return () => clearTimeout(timer);
} }
}, [duration, onClose]); }, [message, duration, onClose]);
const icons = { const icons = {
success: 'check-circle-fill', success: 'check-circle-fill',
@ -20,22 +20,21 @@ const Snackbar = ({ type = 'primary', message, duration = 3000, onClose }) => {
danger: 'exclamation-triangle-fill', danger: 'exclamation-triangle-fill',
}; };
//
const handleClose = (e) => {
e.preventDefault();
if (onClose) onClose();
};
return ( return (
<> <div
<div className={`snackbar alert alert-${type} d-flex align-items-center justify-content-between position-fixed top-10 start-50 translate-middle w-50 z-2 gap-2`}
className={`snackbar alert alert-${type} d-flex align-items-center justify-content-between position-fixed top-10 start-50 translate-middle w-50 alert-dismissible z-2 gap-2`} role='alert'
role='alert' >
> <SvgIcon className={icons[type]} />
<SvgIcon className={icons[type]} /> <div className='flex-fill'>{message}</div>
<div className='flex-fill'>{message}</div> <button type='button' className='btn-close flex-end' onClick={handleClose} aria-label='Close'></button>
<button </div>
type='button'
className='btn-close flex-end'
data-bs-dismiss='alert'
aria-label='Close'
></button>
</div>
</>
); );
}; };

View File

@ -7,7 +7,6 @@ export default function Mainlayout({ children }) {
return ( return (
<> <>
<HeaderWithNav /> <HeaderWithNav />
<NotificationSnackbar />
{children} {children}
</> </>
); );

View File

@ -18,10 +18,11 @@ export default function ChatWindow({ chatId, knowledgeBaseId }) {
error: messagesError, error: messagesError,
} = useSelector((state) => state.chat.messages); } = useSelector((state) => state.chat.messages);
const { status: sendStatus, error: sendError } = useSelector((state) => state.chat.sendMessage); const { status: sendStatus, error: sendError } = useSelector((state) => state.chat.sendMessage);
const knowledgeBase = useSelector((state) =>
state.knowledgeBase.list.data?.items?.find((kb) => kb.id === knowledgeBaseId) // 使Redux
); const knowledgeBases = useSelector((state) => state.knowledgeBase.knowledgeBases || []);
const isLoadingKnowledgeBases = useSelector((state) => state.knowledgeBase.list.isLoading); const knowledgeBase = knowledgeBases.find((kb) => kb.id === knowledgeBaseId);
const isLoadingKnowledgeBases = useSelector((state) => state.knowledgeBase.loading);
// //
useEffect(() => { useEffect(() => {
@ -56,7 +57,7 @@ export default function ChatWindow({ chatId, knowledgeBaseId }) {
// Redux store // Redux store
useEffect(() => { useEffect(() => {
if (!knowledgeBase && !isLoadingKnowledgeBases) { if (!knowledgeBase && !isLoadingKnowledgeBases) {
dispatch(fetchKnowledgeBases()); dispatch(fetchKnowledgeBases({ page: 1, page_size: 50 }));
} }
}, [dispatch, knowledgeBase, isLoadingKnowledgeBases]); }, [dispatch, knowledgeBase, isLoadingKnowledgeBases]);

View File

@ -8,23 +8,20 @@ import SvgIcon from '../../components/SvgIcon';
export default function NewChat() { export default function NewChat() {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const [loading, setLoading] = useState(true);
// Redux store // Redux store - 使
const { data, status, error } = useSelector((state) => state.knowledgeBase.list); const knowledgeBases = useSelector((state) => state.knowledgeBase.knowledgeBases || []);
const knowledgeBases = data?.items || []; const isLoading = useSelector((state) => state.knowledgeBase.loading);
const isLoading = status === 'loading'; const error = useSelector((state) => state.knowledgeBase.error);
// //
useEffect(() => { useEffect(() => {
if (!data?.items?.length && status !== 'loading') { dispatch(fetchKnowledgeBases({ page: 1, page_size: 50 }));
dispatch(fetchKnowledgeBases()); }, [dispatch]);
}
}, [dispatch, data, status]);
// //
useEffect(() => { useEffect(() => {
if (status === 'failed' && error) { if (error) {
dispatch( dispatch(
showNotification({ showNotification({
message: `获取知识库列表失败: ${error.message || error}`, message: `获取知识库列表失败: ${error.message || error}`,
@ -32,7 +29,7 @@ export default function NewChat() {
}) })
); );
} }
}, [status, error, dispatch]); }, [error, dispatch]);
// can_read // can_read
const readableKnowledgeBases = knowledgeBases.filter((kb) => kb.permissions && kb.permissions.can_read === true); const readableKnowledgeBases = knowledgeBases.filter((kb) => kb.permissions && kb.permissions.can_read === true);

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom'; import { useParams, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { showNotification } from '../../../store/notification.slice'; import { showNotification } from '../../../store/notification.slice';
import { getKnowledgeBaseById } from '../../../store/knowledgeBase/knowledgeBase.thunks'; import { fetchKnowledgeBaseDetail } from '../../../store/knowledgeBase/knowledgeBase.thunks';
import SvgIcon from '../../../components/SvgIcon'; import SvgIcon from '../../../components/SvgIcon';
import DatasetTab from './DatasetTab'; import DatasetTab from './DatasetTab';
import SettingsTab from './SettingsTab'; import SettingsTab from './SettingsTab';
@ -13,14 +13,15 @@ export default function KnowledgeBaseDetail() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [activeTab, setActiveTab] = useState(tab === 'settings' ? 'settings' : 'datasets'); const [activeTab, setActiveTab] = useState(tab === 'settings' ? 'settings' : 'datasets');
// Get knowledge base details from Redux store // Get knowledge base details from Redux store - 使
const { data: knowledgeBase, status, error } = useSelector((state) => state.knowledgeBase.detail); const knowledgeBase = useSelector((state) => state.knowledgeBase.currentKnowledgeBase);
const isLoading = status === 'loading'; const loading = useSelector((state) => state.knowledgeBase.loading);
const error = useSelector((state) => state.knowledgeBase.error);
// Fetch knowledge base details when component mounts or ID changes // Fetch knowledge base details when component mounts or ID changes
useEffect(() => { useEffect(() => {
if (id) { if (id) {
dispatch(getKnowledgeBaseById(id)); dispatch(fetchKnowledgeBaseDetail(id));
} }
}, [dispatch, id]); }, [dispatch, id]);
@ -33,7 +34,7 @@ export default function KnowledgeBaseDetail() {
// If knowledge base not found, show notification and redirect // If knowledge base not found, show notification and redirect
useEffect(() => { useEffect(() => {
if (status === 'failed' && error) { if (!loading && error) {
dispatch( dispatch(
showNotification({ showNotification({
message: `获取知识库失败: ${error.message || '未找到知识库'}`, message: `获取知识库失败: ${error.message || '未找到知识库'}`,
@ -42,7 +43,7 @@ export default function KnowledgeBaseDetail() {
); );
navigate('/knowledge-base'); navigate('/knowledge-base');
} }
}, [status, error, dispatch, navigate]); }, [loading, error, dispatch, navigate]);
// Handle tab change // Handle tab change
const handleTabChange = (tab) => { const handleTabChange = (tab) => {
@ -51,7 +52,7 @@ export default function KnowledgeBaseDetail() {
}; };
// Show loading state if knowledge base not loaded yet // Show loading state if knowledge base not loaded yet
if (isLoading || !knowledgeBase) { if (loading || !knowledgeBase) {
return ( return (
<div className='container-fluid px-4 py-5 text-center'> <div className='container-fluid px-4 py-5 text-center'>
<div className='spinner-border' role='status'> <div className='spinner-border' role='status'>

View File

@ -16,7 +16,6 @@ import CreateKnowledgeBaseModal from '../../components/CreateKnowledgeBaseModal'
import Pagination from '../../components/Pagination'; import Pagination from '../../components/Pagination';
import SearchBar from '../../components/SearchBar'; import SearchBar from '../../components/SearchBar';
import ApiModeSwitch from '../../components/ApiModeSwitch'; import ApiModeSwitch from '../../components/ApiModeSwitch';
import debounce from 'lodash/debounce';
// //
import KnowledgeBaseList from './components/KnowledgeBaseList'; import KnowledgeBaseList from './components/KnowledgeBaseList';
@ -47,7 +46,7 @@ export default function KnowledgeBase() {
// Search state // Search state
const [searchKeyword, setSearchKeyword] = useState(''); const [searchKeyword, setSearchKeyword] = useState('');
const [isSearching, setIsSearching] = useState(false); const [isSearchDropdownOpen, setIsSearchDropdownOpen] = useState(false);
// Pagination state // Pagination state
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
@ -68,100 +67,26 @@ export default function KnowledgeBase() {
const searchResults = useSelector((state) => state.knowledgeBase.searchResults); const searchResults = useSelector((state) => state.knowledgeBase.searchResults);
const searchLoading = useSelector((state) => state.knowledgeBase.searchLoading); const searchLoading = useSelector((state) => state.knowledgeBase.searchLoading);
// Determine which data to display based on search state
const displayData = isSearching ? searchResults : knowledgeBases;
const displayTotal = paginationData.total;
const displayStatus = loading ? 'loading' : 'succeeded';
const displayError = error;
// Fetch knowledge bases when component mounts or pagination changes // Fetch knowledge bases when component mounts or pagination changes
useEffect(() => { useEffect(() => {
if (!isSearching) { //
dispatch(fetchKnowledgeBases(pagination)); dispatch(fetchKnowledgeBases(pagination));
} else if (searchKeyword.trim()) { }, [dispatch, pagination.page, pagination.page_size]);
dispatch(
searchKnowledgeBases({
keyword: searchKeyword,
page: pagination.page,
page_size: pagination.page_size,
})
);
}
}, [dispatch, pagination.page, pagination.page_size, isSearching, searchKeyword]);
//
const debouncedSearch = useCallback(
debounce((keyword) => {
if (keyword.trim()) {
dispatch(
searchKnowledgeBases({
keyword,
page: 1,
page_size: 5,
})
);
} else {
dispatch(clearSearchResults());
}
}, 300),
[dispatch]
);
// Handle search input change
const handleSearchInputChange = (e) => {
const value = e.target.value;
setSearchKeyword(value);
//
if (value.trim()) {
debouncedSearch(value);
} else {
dispatch(clearSearchResults());
}
};
// Handle search submit
const handleSearch = (e) => {
e.preventDefault();
if (searchKeyword.trim()) {
setIsSearching(true);
setPagination((prev) => ({ ...prev, page: 1 })); // Reset to first page
dispatch(
searchKnowledgeBases({
keyword: searchKeyword,
page: 1,
page_size: pagination.page_size,
})
);
} else {
// If search is empty, reset to normal list view
handleClearSearch();
}
};
// Handle clear search
const handleClearSearch = () => {
setSearchKeyword('');
setIsSearching(false);
setPagination((prev) => ({ ...prev, page: 1 })); // Reset to first page
dispatch(clearSearchResults());
};
// Show loading state while fetching data // Show loading state while fetching data
const isLoading = displayStatus === 'loading'; const isLoading = loading;
// Show error notification if fetch fails // Show error notification if fetch fails
useEffect(() => { useEffect(() => {
if (displayStatus === 'failed' && displayError) { if (!isLoading && error) {
dispatch( dispatch(
showNotification({ showNotification({
message: `获取知识库列表失败: ${displayError.message || displayError}`, message: `获取知识库列表失败: ${error.message || error}`,
type: 'danger', type: 'danger',
}) })
); );
} }
}, [displayStatus, displayError, dispatch]); }, [isLoading, error, dispatch]);
// Show notification for operation status // Show notification for operation status
useEffect(() => { useEffect(() => {
@ -169,17 +94,7 @@ export default function KnowledgeBase() {
// //
// Refresh the list after successful operation // Refresh the list after successful operation
if (isSearching && searchKeyword.trim()) { dispatch(fetchKnowledgeBases(pagination));
dispatch(
searchKnowledgeBases({
keyword: searchKeyword,
page: pagination.page,
page_size: pagination.page_size,
})
);
} else {
dispatch(fetchKnowledgeBases(pagination));
}
} else if (operationStatus === 'failed' && operationError) { } else if (operationStatus === 'failed' && operationError) {
dispatch( dispatch(
showNotification({ showNotification({
@ -188,7 +103,47 @@ export default function KnowledgeBase() {
}) })
); );
} }
}, [operationStatus, operationError, dispatch, pagination, isSearching, searchKeyword]); }, [operationStatus, operationError, dispatch, pagination]);
// Handle search input change
const handleSearchInputChange = (e) => {
const value = e.target.value;
setSearchKeyword(value);
//
if (!value.trim()) {
dispatch(clearSearchResults());
setIsSearchDropdownOpen(false);
}
};
// Handle search submit -
const handleSearch = (e) => {
e.preventDefault();
if (searchKeyword.trim()) {
// isSearching
dispatch(
searchKnowledgeBases({
keyword: searchKeyword,
page: 1,
page_size: 5, //
})
);
setIsSearchDropdownOpen(true);
} else {
//
handleClearSearch();
}
};
// Handle clear search
const handleClearSearch = () => {
setSearchKeyword('');
//
setIsSearchDropdownOpen(false);
dispatch(clearSearchResults());
};
// Handle pagination change // Handle pagination change
const handlePageChange = (newPage) => { const handlePageChange = (newPage) => {
@ -426,7 +381,7 @@ export default function KnowledgeBase() {
}; };
// Calculate total pages // Calculate total pages
const totalPages = Math.ceil(displayTotal / pagination.page_size); const totalPages = Math.ceil(paginationData.total / pagination.page_size);
// //
const handleOpenCreateModal = () => { const handleOpenCreateModal = () => {
@ -458,7 +413,7 @@ export default function KnowledgeBase() {
<div className='d-flex justify-content-between align-items-center mb-3'> <div className='d-flex justify-content-between align-items-center mb-3'>
<SearchBar <SearchBar
searchKeyword={searchKeyword} searchKeyword={searchKeyword}
isSearching={isSearching} isSearching={isSearchDropdownOpen} //
onSearchChange={handleSearchInputChange} onSearchChange={handleSearchInputChange}
onSearch={handleSearch} onSearch={handleSearch}
onClearSearch={handleClearSearch} onClearSearch={handleClearSearch}
@ -474,12 +429,6 @@ export default function KnowledgeBase() {
</button> </button>
</div> </div>
{isSearching && (
<div className='alert alert-info'>
搜索结果: "{searchKeyword}" - 找到 {displayTotal} 个知识库
</div>
)}
{isLoading ? ( {isLoading ? (
<div className='d-flex justify-content-center my-5'> <div className='d-flex justify-content-center my-5'>
<div className='spinner-border' role='status'> <div className='spinner-border' role='status'>
@ -489,14 +438,14 @@ export default function KnowledgeBase() {
) : ( ) : (
<> <>
<KnowledgeBaseList <KnowledgeBaseList
knowledgeBases={displayData} knowledgeBases={knowledgeBases}
isSearching={isSearching} isSearching={false} // false
onCardClick={handleCardClick} onCardClick={handleCardClick}
onRequestAccess={handleRequestAccess} onRequestAccess={handleRequestAccess}
onDelete={handleDelete} onDelete={handleDelete}
/> />
{/* Pagination */} {/* Pagination - 始终显示 */}
{totalPages > 1 && ( {totalPages > 1 && (
<Pagination <Pagination
currentPage={pagination.page} currentPage={pagination.page}

View File

@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import { checkAuthThunk, loginThunk } from '../../store/auth/auth.thunk'; import { checkAuthThunk, loginThunk } from '../../store/auth/auth.thunk';
import { showNotification } from '../../store/notification.slice';
export default function Login() { export default function Login() {
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -10,6 +11,7 @@ export default function Login() {
const [password, setPassword] = useState('leader123'); const [password, setPassword] = useState('leader123');
const [errors, setErrors] = useState({}); const [errors, setErrors] = useState({});
const [submitted, setSubmitted] = useState(false); const [submitted, setSubmitted] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const { user } = useSelector((state) => state.auth); const { user } = useSelector((state) => state.auth);
@ -22,18 +24,20 @@ export default function Login() {
try { try {
await dispatch(checkAuthThunk()).unwrap(); await dispatch(checkAuthThunk()).unwrap();
if (user) navigate('/'); if (user) navigate('/');
} catch (error) {} } catch (error) {
//
}
}; };
const validateForm = () => { const validateForm = () => {
const newErrors = {}; const newErrors = {};
if (!username) { if (!username) {
newErrors.username = 'Username is required'; newErrors.username = '请输入用户名';
} }
if (!password) { if (!password) {
newErrors.password = 'Password is required'; newErrors.password = '请输入密码';
} else if (password.length < 6) { } else if (password.length < 6) {
newErrors.password = 'Password must be at least 6 characters'; newErrors.password = '密码长度不能少于6个字符';
} }
setErrors(newErrors); setErrors(newErrors);
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0;
@ -44,17 +48,19 @@ export default function Login() {
setSubmitted(true); setSubmitted(true);
if (validateForm()) { if (validateForm()) {
console.log('Form submitted successfully!'); setIsLoading(true);
console.log('Username:', username);
console.log('Password:', password);
try { try {
await dispatch(loginThunk({ username, password })).unwrap(); await dispatch(loginThunk({ username, password })).unwrap();
navigate('/'); navigate('/');
} catch (error) { } catch (error) {
// thunk
console.error('Login failed:', error); console.error('Login failed:', error);
} finally {
setIsLoading(false);
} }
} }
}; };
return ( return (
<div className='position-absolute top-50 start-50 translate-middle d-flex flex-column gap-4 align-items-center'> <div className='position-absolute top-50 start-50 translate-middle d-flex flex-column gap-4 align-items-center'>
<div className='title text-center h1'>OOIN 智能知识库</div> <div className='title text-center h1'>OOIN 智能知识库</div>
@ -69,7 +75,7 @@ export default function Login() {
type='text' type='text'
className={`form-control form-control-lg${submitted && errors.username ? ' is-invalid' : ''}`} className={`form-control form-control-lg${submitted && errors.username ? ' is-invalid' : ''}`}
id='username' id='username'
placeholder='Username' placeholder='用户名'
required required
onChange={(e) => setUsername(e.target.value.trim())} onChange={(e) => setUsername(e.target.value.trim())}
></input> ></input>
@ -80,7 +86,7 @@ export default function Login() {
value={password} value={password}
type='password' type='password'
id='password' id='password'
placeholder='Password' placeholder='密码'
required required
className={`form-control form-control-lg${submitted && errors.password ? ' is-invalid' : ''}`} className={`form-control form-control-lg${submitted && errors.password ? ' is-invalid' : ''}`}
aria-describedby='passwordHelpBlock' aria-describedby='passwordHelpBlock'
@ -89,14 +95,25 @@ export default function Login() {
{submitted && errors.password && <div className='invalid-feedback'>{errors.password}</div>} {submitted && errors.password && <div className='invalid-feedback'>{errors.password}</div>}
</div> </div>
<Link to='#' className='find-password text-body-secondary'> <Link to='#' className='find-password text-body-secondary'>
Forgot password? 忘记密码?
</Link> </Link>
<button type='submit' className='btn btn-dark btn-lg w-100'> <button type='submit' className='btn btn-dark btn-lg w-100' disabled={isLoading}>
Login {isLoading ? (
<>
<span
className='spinner-border spinner-border-sm me-2'
role='status'
aria-hidden='true'
></span>
登录中...
</>
) : (
'登录'
)}
</button> </button>
</form> </form>
<Link to='/signup' className='go-to-signup w-100 link-underline-light h5 text-center'> <Link to='/signup' className='go-to-signup w-100 link-underline-light h5 text-center'>
Need Account? 没有账号去注册
</Link> </Link>
</div> </div>
); );

View File

@ -10,6 +10,7 @@ import Login from '../pages/Auth/Login';
import Signup from '../pages/Auth/Signup'; import Signup from '../pages/Auth/Signup';
import ProtectedRoute from './protectedRoute'; import ProtectedRoute from './protectedRoute';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import NotificationSnackbar from '../components/NotificationSnackbar';
function AppRouter() { function AppRouter() {
const { user } = useSelector((state) => state.auth); const { user } = useSelector((state) => state.auth);
@ -19,6 +20,8 @@ function AppRouter() {
return ( return (
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
<NotificationSnackbar />
<Routes> <Routes>
<Route element={<ProtectedRoute />}> <Route element={<ProtectedRoute />}>
<Route <Route

View File

@ -100,8 +100,8 @@ const get = async (url, params = {}) => {
console.log(`[MOCK MODE] GET ${url}`); console.log(`[MOCK MODE] GET ${url}`);
return await mockGet(url, params); return await mockGet(url, params);
} }
const res = await api.get(url, { params }); const res = await api.get(url, { ...params });
return res.data; return res.data;
} catch (error) { } catch (error) {
if (!hasCheckedServer || (error.request && !error.response)) { if (!hasCheckedServer || (error.request && !error.response)) {

View File

@ -10,9 +10,12 @@ export const loginThunk = createAsyncThunk(
'auth/login', 'auth/login',
async ({ username, password }, { rejectWithValue, dispatch }) => { async ({ username, password }, { rejectWithValue, dispatch }) => {
try { try {
const { message, data } = await post('/auth/login/', { username, password }); const { message, data, code } = await post('/auth/login/', { username, password });
console.log('data', data); console.log('code', code);
if (code !== 200) {
throw new Error(message || 'Something went wrong');
}
if (!data) { if (!data) {
throw new Error(message || 'Something went wrong'); throw new Error(message || 'Something went wrong');
} }
@ -24,6 +27,7 @@ export const loginThunk = createAsyncThunk(
return data; return data;
} catch (error) { } catch (error) {
const errorMessage = error.response?.data?.message || 'Something went wrong'; const errorMessage = error.response?.data?.message || 'Something went wrong';
console.log(errorMessage);
dispatch( dispatch(
showNotification({ showNotification({
message: errorMessage, message: errorMessage,

View File

@ -34,7 +34,7 @@ export const fetchKnowledgeBases = createAsyncThunk(
export const searchKnowledgeBases = createAsyncThunk('knowledgeBase/search', async (params, { rejectWithValue }) => { export const searchKnowledgeBases = createAsyncThunk('knowledgeBase/search', async (params, { rejectWithValue }) => {
try { try {
const { keyword, page = 1, page_size = 10 } = params; const { keyword, page = 1, page_size = 10 } = params;
const response = await get('/knowledge-bases/search/', { const response = await get('/knowledge-bases/search', {
params: { params: {
keyword, keyword,
page, page,