feat: remeber file list view
This commit is contained in:
+5
-2
@@ -1,6 +1,6 @@
|
||||
// const BASE_URL = `${location.origin}/api`;
|
||||
const BASE_URL = `https://dev.rustchat.com/api`;
|
||||
export const CACHE_VERSION = `0.2.1`;
|
||||
export const CACHE_VERSION = `0.3`;
|
||||
// const BASE_URL = `https://rustchat.net/api`;
|
||||
export const ContentTypes = {
|
||||
text: "text/plain",
|
||||
@@ -24,5 +24,8 @@ export const KEY_DEVICE_KEY = "RUSTCHAT_DEVICE_KEY";
|
||||
export const KEY_USERS_VERSION = "RUSTCHAT_USERS_VERSION";
|
||||
export const KEY_AFTER_MID = "RUSTCHAT_AFTER_MID";
|
||||
export const Emojis = ["👍", "❤️", "😄", "👀", "👎", "🎉", "🙁", "🚀"];
|
||||
|
||||
export const Views = {
|
||||
item: "item",
|
||||
grid: "grid",
|
||||
};
|
||||
export default BASE_URL;
|
||||
|
||||
@@ -17,6 +17,11 @@ export default async function handler({ operation, data = {} }) {
|
||||
await table.setItem("inputMode", data.inputMode);
|
||||
}
|
||||
break;
|
||||
case "updateFileListView":
|
||||
{
|
||||
await table.setItem("fileListView", data.fileListView);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
import { Views } from "../config";
|
||||
const initialState = {
|
||||
online: true,
|
||||
ready: false,
|
||||
@@ -7,6 +7,7 @@ const initialState = {
|
||||
menuExpand: false,
|
||||
setting: false,
|
||||
channelSetting: null,
|
||||
fileListView: Views.item,
|
||||
};
|
||||
const uiSlice = createSlice({
|
||||
name: "ui",
|
||||
@@ -27,6 +28,9 @@ const uiSlice = createSlice({
|
||||
updateInputMode(state, action) {
|
||||
state.inputMode = action.payload;
|
||||
},
|
||||
updateFileListView(state, action) {
|
||||
state.fileListView = action.payload;
|
||||
},
|
||||
toggleSetting(state) {
|
||||
state.setting = !state.setting;
|
||||
},
|
||||
@@ -45,5 +49,6 @@ export const {
|
||||
toggleSetting,
|
||||
toggleMenuExpand,
|
||||
toggleChannelSetting,
|
||||
updateFileListView,
|
||||
} = uiSlice.actions;
|
||||
export default uiSlice.reducer;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// import React from 'react'
|
||||
// import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import CheckSign from "../../../assets/icons/check.sign.svg";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 12px;
|
||||
background: #ffffff;
|
||||
min-width: 200px;
|
||||
/* max-height: 230px; */
|
||||
overflow: auto;
|
||||
box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
> .list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
.type {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #616161;
|
||||
.icon {
|
||||
width: 15px;
|
||||
height: auto;
|
||||
}
|
||||
.check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const Dates = {
|
||||
today: {
|
||||
title: "Today",
|
||||
duration: 2222,
|
||||
},
|
||||
in7d: {
|
||||
title: "Last 7 Days",
|
||||
},
|
||||
in30d: {
|
||||
title: "Last 30 Days",
|
||||
},
|
||||
in3m: {
|
||||
title: "Last 3 months",
|
||||
},
|
||||
in12m: {
|
||||
title: "Last 12 months",
|
||||
},
|
||||
};
|
||||
export default function Date({ select = "", updateFilter }) {
|
||||
// const { input, updateInput, contacts } = useFilteredUsers();
|
||||
// const contacts=useSelector(store=>store.contacts);
|
||||
|
||||
// const uid=contacts.ids;
|
||||
// const dataMap=contacts.byId;
|
||||
const handleClick = (dur) => {
|
||||
updateFilter({ date: dur });
|
||||
};
|
||||
return (
|
||||
<Styled>
|
||||
<ul className="list">
|
||||
<li className="type" onClick={handleClick.bind(null, undefined)}>
|
||||
Any Time
|
||||
{!select && <CheckSign className="check" />}
|
||||
</li>
|
||||
{Object.entries(Dates).map(([_key, { title }]) => {
|
||||
return (
|
||||
<li
|
||||
key={title}
|
||||
className="type"
|
||||
onClick={handleClick.bind(null, _key)}
|
||||
>
|
||||
{title}
|
||||
{select == _key && <CheckSign className="check" />}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Styled>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// import React from 'react'
|
||||
import { useSelector } from "react-redux";
|
||||
// import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import Search from "../Search";
|
||||
import CheckSign from "../../../assets/icons/check.sign.svg";
|
||||
@@ -9,7 +9,7 @@ import useFilteredUsers from "../../../common/hook/useFilteredUsers";
|
||||
const Styled = styled.div`
|
||||
padding: 0 4px 4px 4px;
|
||||
background: #ffffff;
|
||||
max-height: 230px;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18);
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// import React from 'react'
|
||||
import { useSelector } from "react-redux";
|
||||
// import { useSelector } from "react-redux";
|
||||
import styled from "styled-components";
|
||||
import IconPdf from "../../../assets/icons/file.pdf.svg";
|
||||
import IconAudio from "../../../assets/icons/file.audio.svg";
|
||||
@@ -83,8 +83,8 @@ export default function Type({ select = "", updateFilter }) {
|
||||
|
||||
// const uid=contacts.ids;
|
||||
// const dataMap=contacts.byId;
|
||||
const handleClick = (uid) => {
|
||||
updateFilter({ type: uid });
|
||||
const handleClick = (type) => {
|
||||
updateFilter({ type });
|
||||
};
|
||||
return (
|
||||
<Styled>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// import React from "react";
|
||||
import { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { FileTypes } from "./Type";
|
||||
import Avatar from "../../../common/component/Avatar";
|
||||
import FilterDate, { Dates } from "./Date";
|
||||
import FilterFrom from "./From";
|
||||
import FilterChannel from "./Channel";
|
||||
import FilterType from "./Type";
|
||||
import FilterType, { FileTypes } from "./Type";
|
||||
import ArrowDown from "../../../assets/icons/arrow.down.svg";
|
||||
const Styled = styled.div`
|
||||
/* padding: 20px 0; */
|
||||
@@ -43,22 +43,53 @@ const Styled = styled.div`
|
||||
`;
|
||||
|
||||
export default function Filter({ filter, updateFilter }) {
|
||||
const [filtersVisible, setFiltersVisible] = useState({
|
||||
channel: false,
|
||||
date: false,
|
||||
from: false,
|
||||
type: false,
|
||||
});
|
||||
const toggleFilterVisible = (obj) => {
|
||||
setFiltersVisible((prev) => {
|
||||
return { ...prev, ...obj };
|
||||
});
|
||||
};
|
||||
const handleUpdateFilter = (data) => {
|
||||
updateFilter(data);
|
||||
let _key = Object.keys(data)[0];
|
||||
let tmp = {
|
||||
[_key]: false,
|
||||
};
|
||||
console.log("wtffff", tmp);
|
||||
toggleFilterVisible(tmp);
|
||||
};
|
||||
const { contactMap, channelMap } = useSelector((store) => {
|
||||
return { contactMap: store.contacts.byId, channelMap: store.channels.byId };
|
||||
});
|
||||
console.log("maps", contactMap, filter);
|
||||
const { from, channel, type } = filter;
|
||||
const { from, channel, type, date } = filter;
|
||||
const {
|
||||
channel: channelVisible,
|
||||
date: dateVisible,
|
||||
type: typeVisible,
|
||||
from: fromVisible,
|
||||
} = filtersVisible;
|
||||
return (
|
||||
<Styled>
|
||||
<Tippy
|
||||
interactive
|
||||
onClickOutside={toggleFilterVisible.bind(null, { from: false })}
|
||||
visible={fromVisible}
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
content={
|
||||
<FilterFrom select={filter.from} updateFilter={updateFilter} />
|
||||
<FilterFrom select={filter.from} updateFilter={handleUpdateFilter} />
|
||||
}
|
||||
>
|
||||
<div className={`filter ${from && "selected"}`}>
|
||||
<div
|
||||
className={`filter ${from && "selected"}`}
|
||||
onClick={toggleFilterVisible.bind(null, { from: true })}
|
||||
>
|
||||
{from && (
|
||||
<Avatar
|
||||
className="avatar"
|
||||
@@ -72,13 +103,21 @@ export default function Filter({ filter, updateFilter }) {
|
||||
</Tippy>
|
||||
<Tippy
|
||||
interactive
|
||||
onClickOutside={toggleFilterVisible.bind(null, { channel: false })}
|
||||
visible={channelVisible}
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
content={
|
||||
<FilterChannel select={filter.channel} updateFilter={updateFilter} />
|
||||
<FilterChannel
|
||||
select={filter.channel}
|
||||
updateFilter={handleUpdateFilter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className={`filter ${channel && "selected"}`}>
|
||||
<div
|
||||
className={`filter ${channel && "selected"}`}
|
||||
onClick={toggleFilterVisible.bind(null, { channel: true })}
|
||||
>
|
||||
<span className="txt">
|
||||
{channel ? `In ${channelMap[channel].name}` : `Channel`}
|
||||
</span>
|
||||
@@ -87,17 +126,40 @@ export default function Filter({ filter, updateFilter }) {
|
||||
</Tippy>
|
||||
<Tippy
|
||||
interactive
|
||||
onClickOutside={toggleFilterVisible.bind(null, { type: false })}
|
||||
visible={typeVisible}
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
content={
|
||||
<FilterType select={filter.type} updateFilter={updateFilter} />
|
||||
<FilterType select={filter.type} updateFilter={handleUpdateFilter} />
|
||||
}
|
||||
>
|
||||
<div className={`filter ${type && "selected"}`}>
|
||||
<div
|
||||
className={`filter ${type && "selected"}`}
|
||||
onClick={toggleFilterVisible.bind(null, { type: true })}
|
||||
>
|
||||
<span className="txt">{type ? FileTypes[type].title : "Type"}</span>
|
||||
<ArrowDown className="arrow" />
|
||||
</div>
|
||||
</Tippy>
|
||||
<Tippy
|
||||
interactive
|
||||
onClickOutside={toggleFilterVisible.bind(null, { date: false })}
|
||||
visible={dateVisible}
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
content={
|
||||
<FilterDate select={filter.date} updateFilter={handleUpdateFilter} />
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={`filter ${date && "selected"}`}
|
||||
onClick={toggleFilterVisible.bind(null, { date: true })}
|
||||
>
|
||||
<span className="txt">{date ? Dates[date].title : "Date"}</span>
|
||||
<ArrowDown className="arrow" />
|
||||
</div>
|
||||
</Tippy>
|
||||
</Styled>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,15 @@ export default function Search({
|
||||
embed = false,
|
||||
}) {
|
||||
const handleChange = (evt) => {
|
||||
updateSearchValue(evt.target.value);
|
||||
if (updateSearchValue) {
|
||||
updateSearchValue(evt.target.value);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Styled className={embed ? "embed" : ""}>
|
||||
<input
|
||||
value={value}
|
||||
onChange={updateSearchValue ? handleChange : null}
|
||||
onChange={handleChange}
|
||||
className="search"
|
||||
placeholder="Search..."
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// import React from 'react'
|
||||
import styled from "styled-components";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { updateFileListView } from "../../app/slices/ui";
|
||||
import { Views } from "../../app/config";
|
||||
import IconList from "../../assets/icons/file.list.svg";
|
||||
import IconGrid from "../../assets/icons/file.grid.svg";
|
||||
const Styled = styled.ul`
|
||||
@@ -27,15 +30,13 @@ const Styled = styled.ul`
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const Views = {
|
||||
item: "item",
|
||||
grid: "grid",
|
||||
};
|
||||
export default function View({ view = Views.item, toggleView }) {
|
||||
|
||||
export default function View({ view = Views.item }) {
|
||||
const dispatch = useDispatch();
|
||||
const handleChangeView = (evt) => {
|
||||
const { view: clickView } = evt.currentTarget.dataset;
|
||||
if (clickView == view) return;
|
||||
toggleView();
|
||||
dispatch(updateFileListView(view == Views.item ? Views.grid : Views.item));
|
||||
};
|
||||
return (
|
||||
<Styled className={view}>
|
||||
|
||||
@@ -3,7 +3,8 @@ import Styled from "./styled";
|
||||
import { useSelector } from "react-redux";
|
||||
import Masonry from "masonry-layout";
|
||||
// import waterfall from "waterfall.js/src/waterfall";
|
||||
import View, { Views } from "./View";
|
||||
import { Views } from "../../app/config";
|
||||
import View from "./View";
|
||||
import Search from "./Search";
|
||||
import Filter from "./Filter";
|
||||
import FileBox from "../../common/component/FileBox";
|
||||
@@ -11,14 +12,14 @@ let msnry = null;
|
||||
export default function ResourceManagement() {
|
||||
const listContainerRef = useRef(null);
|
||||
const [filter, setFilter] = useState({});
|
||||
const [view, setView] = useState(Views.item);
|
||||
const { fileMessages, message } = useSelector((store) => {
|
||||
return { message: store.message, fileMessages: store.fileMessage };
|
||||
const { fileMessages, message, view } = useSelector((store) => {
|
||||
return {
|
||||
message: store.message,
|
||||
fileMessages: store.fileMessage,
|
||||
view: store.ui.fileListView,
|
||||
};
|
||||
});
|
||||
|
||||
const toggleView = () => {
|
||||
setView((prev) => (prev == Views.item ? Views.grid : Views.item));
|
||||
};
|
||||
const updateFilter = (data) => {
|
||||
setFilter((prev) => {
|
||||
return { ...prev, ...data };
|
||||
@@ -50,7 +51,7 @@ export default function ResourceManagement() {
|
||||
<div className="divider"></div>
|
||||
<div className="opts">
|
||||
<Filter filter={filter} updateFilter={updateFilter} />
|
||||
<View view={view} toggleView={toggleView} />
|
||||
<View view={view} />
|
||||
</div>
|
||||
<div className={`list ${view}`} ref={listContainerRef}>
|
||||
{fileMessages.map((id) => {
|
||||
|
||||
Reference in New Issue
Block a user