Sidebar and edit updates
This commit is contained in:
parent
d73b194d1f
commit
f13530f043
32 changed files with 3057 additions and 1114 deletions
150
apps/link/app/(main)/_components/SearchBox.tsx
Normal file
150
apps/link/app/(main)/_components/SearchBox.tsx
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
import { FC, useState, useEffect } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
import { Grid, Box, TextField, Autocomplete } from "@mui/material";
|
||||
import { searchQuery } from "@/app/_graphql/searchQuery";
|
||||
import { colors } from "@/app/_styles/theme";
|
||||
|
||||
type SearchResultProps = {
|
||||
props: any;
|
||||
option: any;
|
||||
};
|
||||
|
||||
const SearchInput = (params: any) => (
|
||||
<TextField
|
||||
{...params}
|
||||
placeholder="Search"
|
||||
sx={{
|
||||
backgroundColor: "white",
|
||||
borderRadius: 10,
|
||||
"& .MuiOutlinedInput-root": {
|
||||
borderRadius: 10,
|
||||
py: 0,
|
||||
legend: {
|
||||
marginLeft: "30px",
|
||||
},
|
||||
},
|
||||
"& .MuiAutocomplete-inputRoot": {
|
||||
paddingLeft: "20px !important",
|
||||
borderRadius: 10,
|
||||
},
|
||||
"& .MuiInputLabel-outlined": {
|
||||
paddingLeft: "20px",
|
||||
},
|
||||
"& .MuiInputLabel-shrink": {
|
||||
marginLeft: "20px",
|
||||
paddingLeft: "10px",
|
||||
paddingRight: 0,
|
||||
background: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const SearchResult: FC<SearchResultProps> = ({ props, option }) => {
|
||||
console.log({ option });
|
||||
|
||||
const { lightGrey, mediumGray, black, white } = colors;
|
||||
|
||||
return (
|
||||
<Box
|
||||
{...props}
|
||||
sx={{
|
||||
px: 2,
|
||||
py: 1.25,
|
||||
":hover": {
|
||||
background: `${lightGrey}`,
|
||||
},
|
||||
a: {
|
||||
color: `${black} !important`,
|
||||
},
|
||||
borderBottom: `1px solid ${mediumGray}`,
|
||||
}}
|
||||
>
|
||||
<Grid container direction="column" spacing={0.1}>
|
||||
<Grid item container direction="row" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Box
|
||||
sx={{
|
||||
py: 0,
|
||||
fontSize: 13,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
{option.title}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Box
|
||||
sx={{
|
||||
color: "#999",
|
||||
fontSize: 13,
|
||||
wrap: "break-word",
|
||||
}}
|
||||
>
|
||||
{option.note}
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const SearchBox: FC = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedValue, setSelectedValue] = useState(null);
|
||||
const [searchTerms, setSearchTerms] = useState(null);
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const { data, error }: any = useSWR({
|
||||
document: searchQuery,
|
||||
variables: {
|
||||
search: searchTerms ?? "",
|
||||
limit: 50,
|
||||
},
|
||||
refreshInterval: 10000,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
forcePopupIcon={false}
|
||||
openOnFocus
|
||||
blurOnSelect
|
||||
value={selectedValue}
|
||||
onBlur={() => setOpen(false)}
|
||||
inputValue={searchTerms}
|
||||
onChange={(_event, option, reason) => {
|
||||
if (!option) return;
|
||||
const url = `/tickets/${option.internalId}`;
|
||||
setSelectedValue("");
|
||||
router.push(url);
|
||||
}}
|
||||
onInputChange={(_event, value) => {
|
||||
setSearchTerms(value);
|
||||
}}
|
||||
open={open}
|
||||
onOpen={() => setOpen(true)}
|
||||
noOptionsText="No results"
|
||||
options={data?.search ?? []}
|
||||
getOptionLabel={(option: any) => {
|
||||
if (option) {
|
||||
return option.title;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}}
|
||||
renderOption={(props, option: any) => (
|
||||
<SearchResult props={props} key={option.id} option={option} />
|
||||
)}
|
||||
sx={{ width: "100%" }}
|
||||
renderInput={(params: any) => <SearchInput {...params} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useState } from "react";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
import {
|
||||
Box,
|
||||
|
|
@ -26,6 +26,7 @@ import {
|
|||
Assessment as AssessmentIcon,
|
||||
LibraryBooks as LibraryBooksIcon,
|
||||
School as SchoolIcon,
|
||||
Search as SearchIcon,
|
||||
} from "@mui/icons-material";
|
||||
import { usePathname } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
|
|
@ -33,8 +34,8 @@ import Image from "next/image";
|
|||
import LinkLogo from "public/link-logo-small.png";
|
||||
import { useSession, signOut } from "next-auth/react";
|
||||
import { getTicketOverviewCountsQuery } from "app/_graphql/getTicketOverviewCountsQuery";
|
||||
import { SearchBox } from "./SearchBox";
|
||||
|
||||
console.log;
|
||||
const openWidth = 270;
|
||||
const closedWidth = 100;
|
||||
|
||||
|
|
@ -174,13 +175,15 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
|||
},
|
||||
{ refreshInterval: 10000 },
|
||||
);
|
||||
console.log({ overviewData });
|
||||
const findOverviewCountByID = (id: number) =>
|
||||
overviewData?.ticketOverviews?.edges?.find((overview: any) =>
|
||||
overview.node.id.endsWith(`/${id}`),
|
||||
)?.node?.ticketCount ?? 0;
|
||||
const recentCount = 0;
|
||||
const assignedCount = findOverviewCountByID(1);
|
||||
const openCount = findOverviewCountByID(5);
|
||||
const urgentCount = findOverviewCountByID(7);
|
||||
const pendingCount = findOverviewCountByID(3);
|
||||
const unassignedCount = findOverviewCountByID(2);
|
||||
|
||||
const logout = () => {
|
||||
|
|
@ -227,6 +230,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
|||
direction="column"
|
||||
justifyContent="space-between"
|
||||
wrap="nowrap"
|
||||
spacing={0}
|
||||
sx={{ backgroundColor: "#25272A", height: "100%", p: 2 }}
|
||||
>
|
||||
<Grid item container>
|
||||
|
|
@ -313,9 +317,17 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
|||
</Grid>
|
||||
<Grid item>
|
||||
<Box
|
||||
sx={{ height: "0.5px", width: "100%", backgroundColor: "#666" }}
|
||||
sx={{
|
||||
height: "0.5px",
|
||||
width: "100%",
|
||||
backgroundColor: "#666",
|
||||
mb: 2,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<SearchBox />
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
container
|
||||
|
|
@ -377,7 +389,7 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
|||
/>
|
||||
<MenuItem
|
||||
name="Tickets"
|
||||
href="/overview/assigned"
|
||||
href="/overview/recent"
|
||||
Icon={FeaturedPlayListIcon}
|
||||
selected={
|
||||
pathname.startsWith("/overview") ||
|
||||
|
|
@ -397,12 +409,21 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
|||
>
|
||||
<List component="div" disablePadding>
|
||||
<MenuItem
|
||||
name="Assigned"
|
||||
href="/overview/assigned"
|
||||
name="Recent"
|
||||
href="/overview/recent"
|
||||
Icon={FeaturedPlayListIcon}
|
||||
iconSize={0}
|
||||
selected={pathname.endsWith("/overview/assigned")}
|
||||
badge={assignedCount}
|
||||
selected={pathname.endsWith("/overview/recent")}
|
||||
badge={recentCount}
|
||||
open={open}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Open"
|
||||
href="/overview/open"
|
||||
Icon={FeaturedPlayListIcon}
|
||||
iconSize={0}
|
||||
selected={pathname.endsWith("/overview/open")}
|
||||
badge={openCount}
|
||||
open={open}
|
||||
/>
|
||||
<MenuItem
|
||||
|
|
@ -415,12 +436,12 @@ export const Sidebar: FC<SidebarProps> = ({ open, setOpen }) => {
|
|||
open={open}
|
||||
/>
|
||||
<MenuItem
|
||||
name="Pending"
|
||||
href="/overview/pending"
|
||||
name="Assigned"
|
||||
href="/overview/assigned"
|
||||
Icon={FeaturedPlayListIcon}
|
||||
iconSize={0}
|
||||
selected={pathname.endsWith("/overview/pending")}
|
||||
badge={pendingCount}
|
||||
selected={pathname.endsWith("/overview/assigned")}
|
||||
badge={assignedCount}
|
||||
open={open}
|
||||
/>
|
||||
<MenuItem
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useState, useEffect } from "react";
|
||||
import { FC, useState, useEffect, useRef } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Iframe from "react-iframe";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
|
@ -16,7 +16,8 @@ export const ZammadWrapper: FC<ZammadWrapperProps> = ({
|
|||
hideSidebar = true,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { data: session } = useSession();
|
||||
const { data: session } = useSession({ required: true });
|
||||
const timeoutRef = useRef(null);
|
||||
const [authenticated, setAuthenticated] = useState(false);
|
||||
const [display, setDisplay] = useState("none");
|
||||
const url = `/zammad${path}`;
|
||||
|
|
@ -28,7 +29,7 @@ export const ZammadWrapper: FC<ZammadWrapperProps> = ({
|
|||
method: "GET",
|
||||
redirect: "manual",
|
||||
});
|
||||
|
||||
console.log({ res });
|
||||
if (res.type === "opaqueredirect") {
|
||||
setAuthenticated(true);
|
||||
} else {
|
||||
|
|
@ -39,8 +40,24 @@ export const ZammadWrapper: FC<ZammadWrapperProps> = ({
|
|||
checkAuthenticated();
|
||||
}, [path]);
|
||||
|
||||
if (!session) {
|
||||
console.log("No session");
|
||||
useEffect(() => {
|
||||
if (session === null) {
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
if (session === null) {
|
||||
router.push("/login");
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
if (session !== null) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
return () => clearTimeout(timeoutRef.current);
|
||||
}, [session]);
|
||||
|
||||
if (!session || !authenticated) {
|
||||
console.log("Not authenticated");
|
||||
return (
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Grid
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue