feat: user search
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import styled from "styled-components";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import searchIcon from "../../assets/icons/search.svg?url";
|
||||
import addIcon from "../../assets/icons/add.svg?url";
|
||||
import AddEntriesMenu from "../../common/component/AddEntriesMenu";
|
||||
import Tooltip from "../../common/component/Tooltip";
|
||||
import { FC, ChangeEvent } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
position: relative;
|
||||
min-height: 56px;
|
||||
padding: 6px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
|
||||
.search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
.input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: none;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
type Props = {
|
||||
input: string,
|
||||
updateInput: (input: string) => void
|
||||
};
|
||||
const Search: FC<Props> = ({ input, updateInput }) => {
|
||||
const { t } = useTranslation();
|
||||
const handleInput = (evt: ChangeEvent<HTMLInputElement>) => {
|
||||
updateInput(evt.target.value);
|
||||
};
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="search">
|
||||
<img src={searchIcon} alt="search icon" />
|
||||
<input value={input} placeholder={`${t("action.search")}...`} className="input" onChange={handleInput} />
|
||||
</div>
|
||||
<Tooltip tip={t("more")} placement="bottom">
|
||||
<Tippy interactive placement="bottom-end" trigger="click" content={<AddEntriesMenu />}>
|
||||
<img src={addIcon} alt="add icon" className="cursor-pointer" />
|
||||
</Tippy>
|
||||
</Tooltip>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
export default Search;
|
||||
@@ -1,22 +1,21 @@
|
||||
import { memo, useEffect } from "react";
|
||||
import { NavLink, useParams, useLocation } from "react-router-dom";
|
||||
import { useDispatch } from "react-redux";
|
||||
import _ from "lodash";
|
||||
import { updateRememberedNavs } from "../../app/slices/ui";
|
||||
import Search from "../../common/component/Search";
|
||||
import Search from "./Search";
|
||||
import User from "../../common/component/User";
|
||||
import Profile from "../../common/component/Profile";
|
||||
|
||||
import StyledWrapper from "./styled";
|
||||
import BlankPlaceholder from "../../common/component/BlankPlaceholder";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
import useFilteredUsers from "../../common/hook/useFilteredUsers";
|
||||
|
||||
function UsersPage() {
|
||||
const dispatch = useDispatch();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { input, updateInput, users } = useFilteredUsers();
|
||||
const { user_id } = useParams();
|
||||
const userIds = useAppSelector((store) => store.users.ids, _.isEqual);
|
||||
// 记住路由
|
||||
useEffect(() => {
|
||||
dispatch(updateRememberedNavs({ key: "user" }));
|
||||
return () => {
|
||||
@@ -24,14 +23,14 @@ function UsersPage() {
|
||||
};
|
||||
}, [pathname]);
|
||||
|
||||
if (!userIds) return null;
|
||||
if (!users) return null;
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="left">
|
||||
<Search />
|
||||
<Search input={input} updateInput={updateInput} />
|
||||
<div className="list">
|
||||
<nav className="nav">
|
||||
{userIds.map((uid: number) => {
|
||||
{users.map(({ uid }) => {
|
||||
return (
|
||||
<NavLink key={uid} className="session" to={`/users/${uid}`}>
|
||||
<User uid={uid} enableContextMenu={true} />
|
||||
|
||||
Reference in New Issue
Block a user