import * as React from "react";
import * as Constants from "~/common/constants";
import * as SVG from "~/common/svg";
import * as Strings from "~/common/strings";
import * as Actions from "~/common/actions";
import MiniSearch from "minisearch";
import { css } from "@emotion/core";
import { SearchDropdown } from "~/components/core/SearchDropdown";
import { dispatchCustomEvent } from "~/common/custom-events";
import { SlatePreviewRow } from "~/components/core/SlatePreviewBlock";
const STYLES_ICON_CIRCLE = css`
height: 24px;
width: 24px;
border-radius: 50%;
background-color: ${Constants.system.foreground};
display: flex;
align-items: center;
justify-content: center;
`;
const STYLES_CONTAINER = css`
padding: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
background-color: ${Constants.system.white};
box-shadow: 0 0 60px 8px rgba(0, 0, 0, 0.03);
@media (max-width: ${Constants.sizes.mobile}px) {
max-width: 95vw;
padding: 20px;
}
`;
const STYLES_MODAL = css`
position: relative;
width: 95vw;
max-width: 640px;
box-sizing: border-box;
height: 60vh;
max-height: 480px;
`;
const STYLES_SEARCH_DROPDOWN = {
// height: "calc(100% - 16px)",
// overflowY: "scroll",
};
const STYLES_USER_ENTRY_CONTAINER = css`
display: grid;
grid-template-columns: repeat(3, auto) 1fr;
grid-column-gap: 16px;
align-items: center;
`;
const STYLES_PROFILE_IMAGE = css`
background-color: ${Constants.system.foreground};
background-size: cover;
background-position: 50% 50%;
height: 24px;
width: 24px;
border-radius: 50%;
`;
const UserEntry = ({ item }) => {
return (
{item.data.name ?
{item.data.name}
: null}
@{item.username}
);
};
const STYLES_ENTRY = css`
padding: 8px 0px;
`;
const STYLES_SLATE_ENTRY_CONTAINER = css`
display: grid;
grid-template-columns: repeat(3, auto) 1fr;
grid-column-gap: 16px;
align-items: center;
`;
const STYLES_SLATE_IMAGES_CONTAINER = css`
margin-top: 8px;
margin-left: 40px;
`;
const STYLES_TITLE = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
const SlateEntry = ({ item }) => {
return (
{item.data.name}
{item.owner && item.owner.username ? (
@{item.owner.username}
) : null}
{item.data.objects && item.data.objects.length ? (
) : null}
);
};
const FileEntry = ({ item }) => {
return (
{item.data.file.title || item.data.file.name || item.data.file.file}
{item.data.slate && item.data.slate.owner && item.data.slate.owner.username ? (
@{item.data.slate.owner.username}
) : null}
);
};
export class SearchModal extends React.Component {
state = {
loading: true,
results: [],
inputValue: "",
filters: { slates: true },
};
componentDidMount = async () => {
await this.fillDirectory();
// await this.fillPersonalDirectory();
this.setState({ loading: false });
};
fillDirectory = async () => {
const response = await Actions.getNetworkDirectory();
this.miniSearch = new MiniSearch({
fields: ["slatename", "data.name", "username", "filename"],
storeFields: ["type", "slatename", "username", "data", "id", "slates", "owner"],
extractField: (entry, fieldName) => {
return fieldName.split(".").reduce((doc, key) => doc && doc[key], entry);
},
searchOptions: {
fuzzy: 0.15,
},
});
let files = [];
if (response.data) {
for (let slate of response.data.slates) {
if (slate.data.objects.length) {
files.push(
...slate.data.objects.map((file, i) => {
return {
type: "FILE",
id: file.id,
filename: file.title,
data: { file, index: i, slate },
};
})
);
}
}
this.miniSearch.addAll(response.data.users);
this.miniSearch.addAll(response.data.slates);
this.miniSearch.addAll(files);
}
};
fillPersonalDirectory = () => {
this.personalSearch = new MiniSearch({
fields: ["slatename", "data.name", "username", "filename"],
storeFields: ["type", "slatename", "username", "data", "id", "slates", "owner"],
extractField: (entry, fieldName) => {
return fieldName.split(".").reduce((doc, key) => doc && doc[key], entry);
},
searchOptions: {
fuzzy: 0.15,
},
});
let files = this.props.viewer.library[0].children.map((file, i) => {
return {
type: "DATA_FILE",
id: file.id,
filename: file.name || file.file,
data: {
file: {
...file,
url: `${Constants.gateways.ipfs}/${file.cid || file.ipfs.replace("/ipfs/", "")}`,
},
index: i,
},
};
});
let slates = this.props.viewer.slates.map((slate) => {
return { ...slate, type: "SLATE", owner: this.props.viewer };
});
this.personalSearch.addAll(slates);
let userIds = [];
this.personalSearch.addAll(this.props.viewer.pendingTrusted.map((trust) => trust.owner));
userIds.push(...this.props.viewer.pendingTrusted.map((trust) => trust.owner.id));
this.personalSearch.addAll(
this.props.viewer.trusted
.filter((trust) => !userIds.includes(trust.user.id))
.map((trust) => trust.user)
);
userIds.push(...this.props.viewer.trusted.map((trust) => trust.user.id));
this.personalSearch.addAll(
this.props.viewer.subscriptions
.filter((sub) => sub.target_user_id && !userIds.includes(sub.user.id))
.map((sub) => sub.user)
);
this.personalSearch.addAll(files);
};
_handleChange = (e) => {
this.setState({ inputValue: e.target.value });
//interpret the thing with handleInterpret (and change shownValue accordingly)
};
//converts input to search filter options
_handleInterpret = (query) => {
if (query.contains("files:")) {
} else if (query.contains("users:")) {
} else if (query.contains("slates:")) {
} else if (query.contains("tags:")) {
} else if (query.contains("#")) {
} else if (query.contains("@")) {
}
};
_handleSearch = () => {
if (!this.state.loading) {
let searchResults = this.miniSearch.search(this.state.inputValue);
let ids = new Set();
for (let result of searchResults) {
ids.add(result.id);
}
let autofill = this.miniSearch.autoSuggest(this.state.inputValue);
for (let i = 0; i < autofill.length; i++) {
let result = this.miniSearch.search(autofill[i].suggestion)[0];
if (!ids.has(result.id)) {
ids.add(result.id);
searchResults.push(result);
}
}
this.setState({ results: searchResults });
}
};
// _handleSearch = async () => {
// if (this.state.loading) return;
// if (this.state.filters["my"]) {
// let miniSearch = this.personalSearch;
// let filter;
// if (this.state.filters["files"]) {
// filter = {
// filter: (result) => {
// return result.type === "FILE" || result.type === "DATA_FILE";
// },
// };
// } else if (this.state.filters["users"]) {
// filter = {
// filter: (result) => result.type === "USER",
// };
// } else if (this.state.filters["slates"]) {
// filter = {
// filter: (result) => result.type === "SLATE",
// };
// }
// let searchResults;
// if (filter) {
// searchResults = miniSearch.search(this.state.inputValue, filter);
// } else {
// searchResults = miniSearch.search(this.state.inputValue);
// }
// let ids = new Set();
// for (let result of searchResults) {
// ids.add(result.id);
// }
// let autofill = miniSearch.autoSuggest(this.state.inputValue);
// for (let i = 0; i < autofill.length; i++) {
// let result;
// if (Object.keys(this.state.filter).length) {
// result = miniSearch.search(autofill[i].suggestion, this.state.filter);
// } else {
// result = miniSearch.search(autofill[i].suggestion);
// }
// if (result && result.length) {
// result = result[0];
// if (!ids.has(result.id)) {
// ids.add(result.id);
// searchResults.push(result);
// }
// }
// }
// this.setState({ results: searchResults });
// } else {
// const results = await Actions.search({
// query: this.state.inputValue,
// filter: this.state.filters,
// });
// this.setState({ results: results.data.results });
// }
// };
_handleSelect = async (value) => {
if (value.type === "SLATE") {
this.props.onAction({
type: "NAVIGATE",
value: "V1_NAVIGATION_SLATE",
data: value.data,
});
}
if (value.type === "USER") {
this.props.onAction({
type: "NAVIGATE",
value: "V1_NAVIGATION_PROFILE",
data: value.data,
});
}
if (value.type === "DATA_FILE") {
await this.props.onAction({
type: "NAVIGATE",
value: "data",
});
dispatchCustomEvent({
name: "slate-global-open-carousel",
detail: { index: value.data.data.index },
});
}
if (value.type === "FILE") {
await this.props.onAction({
type: "NAVIGATE",
value: "V1_NAVIGATION_SLATE",
data: value.data.data.slate,
});
dispatchCustomEvent({
name: "slate-global-open-carousel",
detail: { index: value.data.data.index },
});
}
dispatchCustomEvent({
name: "delete-modal",
detail: {},
});
};
render() {
let results = [];
for (let item of this.state.results) {
if (item.type === "USER") {
results.push({
value: {
type: "USER",
data: item,
},
component: ,
});
} else if (item.type === "SLATE") {
results.push({
value: {
type: "SLATE",
data: item,
},
component: ,
});
} else if (item.type === "FILE" || item.type === "DATA_FILE") {
results.push({
value: {
type: item.type,
data: item,
},
component: ,
});
}
}
return (
);
}
}