Skip to content

Commit 6bc513f

Browse files
committed
Implemente user search
1 parent ca3b039 commit 6bc513f

File tree

4 files changed

+107
-91
lines changed

4 files changed

+107
-91
lines changed

src/sections/user/user-table-row.jsx

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import PropTypes from 'prop-types';
2+
import { useState, useEffect } from 'react';
23
import { format, formatDistanceToNow } from 'date-fns'
34

45
import Stack from '@mui/material/Stack';
@@ -11,8 +12,43 @@ import Label from 'src/components/label';
1112

1213
// ----------------------------------------------------------------------
1314

15+
function TextHighlight({ text, searchKeyword }) {
16+
const [highlightedText, setHighlightedText] = useState(text);
17+
18+
useEffect(() => {
19+
if (searchKeyword) {
20+
const regex = new RegExp(`(${searchKeyword})`, 'gi');
21+
const parts = text.split(regex);
22+
const newHighlightedText = parts.map((part, i) =>
23+
part.toLowerCase() === searchKeyword.toLowerCase() ? (
24+
<mark key={i}>{part}</mark>
25+
) : (
26+
part
27+
)
28+
);
29+
setHighlightedText(newHighlightedText);
30+
} else {
31+
setHighlightedText(text); // Reset to original text
32+
}
33+
}, [text, searchKeyword]);
34+
35+
return (
36+
<Stack direction="row" spacing={1}>
37+
<Typography variant="subtitle2">
38+
{highlightedText}
39+
</Typography>
40+
</Stack>
41+
);
42+
}
43+
44+
TextHighlight.propTypes = {
45+
text: PropTypes.string.isRequired,
46+
searchKeyword: PropTypes.string,
47+
}
48+
49+
1450
export default function UserTableRow({
15-
selected,
51+
searchTerm,
1652
username,
1753
avatarUrl,
1854
displayName,
@@ -26,13 +62,17 @@ export default function UserTableRow({
2662
<TableCell component="th" scope="row" >
2763
<Stack direction="row" alignItems="center" spacing={2}>
2864
<Avatar alt={username} src={avatarUrl} />
29-
<Typography variant="subtitle2" noWrap>
30-
{username}
31-
</Typography>
65+
<TextHighlight
66+
text={username}
67+
searchKeyword={searchTerm}
68+
/>
3269
</Stack>
3370
</TableCell>
3471

35-
<TableCell>{displayName}</TableCell>
72+
<TableCell><TextHighlight
73+
text={displayName}
74+
searchKeyword={searchTerm}
75+
/></TableCell>
3676

3777
<TableCell>{format(new Date(created_at), 'dd MMMM yyyy')} ({formatDistanceToNow(new Date(created_at), { addSuffix: true })})</TableCell>
3878

@@ -52,6 +92,6 @@ UserTableRow.propTypes = {
5292
location: PropTypes.any,
5393
username: PropTypes.any,
5494
created_at: PropTypes.any,
55-
selected: PropTypes.any,
95+
searchTerm: PropTypes.string,
5696
public_repos: PropTypes.number,
5797
};

src/sections/user/view/user-dialog.jsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ export default function AlertDialog({ open, setOpen, user, setSelectedUser }) {
3333
</DialogContentText>
3434
</DialogContent>
3535
<DialogActions>
36-
<Button onClick={handleClose}>Disagree</Button>
37-
<Button onClick={handleClose} autoFocus>
38-
Agree
39-
</Button>
36+
<Button disabled onClick={handleClose}>Follow</Button>
4037
</DialogActions>
4138
</Dialog>
4239
);

src/sections/user/view/user-profile.jsx

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/sections/user/view/user-view.jsx

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from 'react';
1+
import { useRef, useState, useEffect } from 'react';
22

33
import Card from '@mui/material/Card';
44
import Stack from '@mui/material/Stack';
@@ -15,56 +15,88 @@ import UserDialog from './user-dialog';
1515
import TableNoData from '../table-no-data';
1616
import UserTableRow from '../user-table-row';
1717
import UserTableHead from '../user-table-head';
18-
import TableEmptyRows from '../table-empty-rows';
1918
import UserTableToolbar from '../user-table-toolbar';
20-
import { emptyRows, applyFilter, getComparator } from '../utils';
2119

2220
// ----------------------------------------------------------------------
2321

22+
2423
export default function UserPage() {
2524

25+
const rowsPerPage = 10;
26+
27+
const fetchWrapper = async (url) => {
28+
try {
29+
const response = await fetch(url, {
30+
credentials: 'include',
31+
});
32+
33+
if (!response.ok) {
34+
throw new Error(`HTTP error! status: ${response.status}`);
35+
}
36+
37+
const data = await response.json();
38+
return data;
39+
} catch (error) {
40+
console.error(`Fetch failed: ${error}`);
41+
throw error;
42+
}
43+
};
44+
45+
2646
const [page, setPage] = useState(0);
2747

2848
const [order, setOrder] = useState('asc');
2949

30-
const [orderBy, setOrderBy] = useState('name');
50+
const [orderBy, setOrderBy] = useState('username');
3151

3252
const [filterName, setFilterName] = useState('');
3353

34-
const [rowsPerPage, setRowsPerPage] = useState(5);
35-
3654
// users
3755
const [users, setUsers] = useState([]);
3856
const [selectedUser, setSelectedUser] = useState(null);
57+
const [total, setTotal] = useState(0);
3958

4059
const [openDialog, setOpenDialog] = useState(false);
4160

61+
const prevFilterNameRef = useRef();
62+
4263
useEffect(() => {
4364
const apiUrl = import.meta.env.VITE_API_URL;
65+
const prevFilterName = prevFilterNameRef.current;
66+
67+
console.log('page', page);
68+
4469
const loadUsers = async () => {
4570
try {
4671
// Load users from the backend using fetch
47-
const response = await fetch(`${apiUrl}/v1/users`, {
48-
credentials: 'include' // Crucial setting
49-
});
50-
51-
if (!response.ok) {
52-
// throw new Error('Users fetch failed');
53-
console.error('Users fetch failed', response);
54-
} else {
55-
const data = await response.json();
56-
console.log('Users:', { data });
57-
setUsers(data)
58-
}
59-
60-
72+
const data = await fetchWrapper(`${apiUrl}/v1/users/search?keyword=${filterName}&page=${page}&orderBy=${orderBy}&order=${order}`);
73+
setUsers(data);
6174
} catch (error) {
6275
console.error('Load users error:', error);
6376
}
6477
};
6578

79+
const loadTotal = async () => {
80+
try {
81+
// Load users from the backend using fetch
82+
const count = await fetchWrapper(`${apiUrl}/v1/users/count?keyword=${filterName}`);
83+
setTotal(count.total);
84+
} catch (error) {
85+
console.error('Load total error:', error);
86+
}
87+
};
88+
89+
if (filterName !== prevFilterName) {
90+
setPage(0);
91+
loadTotal();
92+
}
93+
6694
loadUsers();
67-
}, []);
95+
96+
prevFilterNameRef.current = filterName;
97+
98+
}, [filterName, page, order, orderBy]);
99+
68100

69101
const handleSort = (event, id) => {
70102
const isAsc = orderBy === id && order === 'asc';
@@ -78,15 +110,10 @@ export default function UserPage() {
78110
setPage(newPage);
79111
};
80112

81-
const handleChangeRowsPerPage = (event) => {
82-
setPage(0);
83-
setRowsPerPage(parseInt(event.target.value, 10));
84-
};
85-
86113
const handleFilterByName = (event) => {
87114
// setPage(0);
88-
setFilterName(event.target.value);
89115
console.log('handleFilterByName', event.target.value);
116+
setFilterName(event.target.value);
90117
};
91118

92119
const handleClick = async (row) => {
@@ -95,13 +122,6 @@ export default function UserPage() {
95122
setOpenDialog(true);
96123
}
97124

98-
const dataFiltered = applyFilter({
99-
inputData: users,
100-
comparator: getComparator(order, orderBy),
101-
filterName,
102-
});
103-
104-
const notFound = !dataFiltered.length && !!filterName;
105125

106126
return (
107127
<Container>
@@ -133,8 +153,7 @@ export default function UserPage() {
133153
]}
134154
/>
135155
<TableBody>
136-
{dataFiltered
137-
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
156+
{users
138157
.map((row) => (
139158
<UserTableRow
140159
key={row._id}
@@ -145,15 +164,10 @@ export default function UserPage() {
145164
avatarUrl={row.avatarUrl}
146165
public_repos={row.public_repos}
147166
handleClick={(event) => handleClick(row)}
167+
searchTerm={filterName}
148168
/>
149169
))}
150-
151-
<TableEmptyRows
152-
height={77}
153-
emptyRows={emptyRows(page, rowsPerPage, users.length)}
154-
/>
155-
156-
{notFound && <TableNoData query={filterName} />}
170+
{!total && <TableNoData query={filterName} />}
157171
</TableBody>
158172
</Table>
159173
</TableContainer>
@@ -162,11 +176,10 @@ export default function UserPage() {
162176
<TablePagination
163177
page={page}
164178
component="div"
165-
count={users.length}
166-
rowsPerPage={rowsPerPage}
179+
count={total}
167180
onPageChange={handleChangePage}
168-
rowsPerPageOptions={[5, 10, 25]}
169-
onRowsPerPageChange={handleChangeRowsPerPage}
181+
rowsPerPage={rowsPerPage}
182+
rowsPerPageOptions={[]}
170183
/>
171184
</Card>
172185
{selectedUser && <UserDialog open={openDialog} setOpen={setOpenDialog} user={selectedUser} setSelectedUser={setSelectedUser} />}

0 commit comments

Comments
 (0)