Themes modal udpated
This commit is contained in:
@@ -1,18 +1,18 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
env: { browser: true, es2020: true },
|
env: { browser: true, es2020: true },
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
"eslint:recommended",
|
||||||
'plugin:@typescript-eslint/recommended',
|
"plugin:@typescript-eslint/recommended",
|
||||||
'plugin:react-hooks/recommended',
|
"plugin:react-hooks/recommended",
|
||||||
],
|
],
|
||||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
ignorePatterns: ["dist", ".eslintrc.cjs"],
|
||||||
parser: '@typescript-eslint/parser',
|
parser: "@typescript-eslint/parser",
|
||||||
plugins: ['react-refresh'],
|
plugins: ["react-refresh"],
|
||||||
rules: {
|
rules: {
|
||||||
'react-refresh/only-export-components': [
|
"react-refresh/only-export-components": [
|
||||||
'warn',
|
"warn",
|
||||||
{ allowConstantExport: true },
|
{ allowConstantExport: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
86
package.json
86
package.json
@@ -1,45 +1,45 @@
|
|||||||
{
|
{
|
||||||
"name": "triggerfrontend",
|
"name": "triggerfrontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.0",
|
"@emotion/react": "^11.13.0",
|
||||||
"@iconify/react": "^5.0.2",
|
"@iconify/react": "^5.0.2",
|
||||||
"@mantine/core": "^7.12.1",
|
"@mantine/core": "^7.12.1",
|
||||||
"@mantine/dates": "^7.12.1",
|
"@mantine/dates": "^7.12.1",
|
||||||
"@mantine/form": "^7.12.1",
|
"@mantine/form": "^7.12.1",
|
||||||
"@mantine/hooks": "^7.12.1",
|
"@mantine/hooks": "^7.12.1",
|
||||||
"@mantine/modals": "^7.12.1",
|
"@mantine/modals": "^7.12.1",
|
||||||
"@tabler/icons-react": "^3.12.0",
|
"@tabler/icons-react": "^3.12.0",
|
||||||
"@tanstack/react-query": "^5.51.23",
|
"@tanstack/react-query": "^5.51.23",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.12",
|
"dayjs": "^1.11.12",
|
||||||
"jotai": "^2.9.3",
|
"jotai": "^2.9.3",
|
||||||
"mantine-react-table": "^2.0.0-beta.6",
|
"mantine-react-table": "^2.0.0-beta.6",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^5.3.0",
|
"react-icons": "^5.3.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
"react-toastify": "^10.0.5"
|
"react-toastify": "^10.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
||||||
"@typescript-eslint/parser": "^8.1.0",
|
"@typescript-eslint/parser": "^8.1.0",
|
||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"eslint": "^9.9.0",
|
"eslint": "^9.9.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"eslint-plugin-react-refresh": "^0.4.9",
|
"eslint-plugin-react-refresh": "^0.4.9",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"vite": "^5.4.0"
|
"vite": "^5.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
90
src/App.tsx
90
src/App.tsx
@@ -1,66 +1,76 @@
|
|||||||
import Homepage from './pages/homepage/Homepage'
|
import Homepage from "./pages/homepage/Homepage";
|
||||||
import { MantineProvider, DEFAULT_THEME, createTheme, mergeMantineTheme } from '@mantine/core'
|
import {
|
||||||
|
MantineProvider,
|
||||||
|
DEFAULT_THEME,
|
||||||
|
createTheme,
|
||||||
|
mergeMantineTheme,
|
||||||
|
} from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
Route,
|
Route,
|
||||||
createBrowserRouter,
|
createBrowserRouter,
|
||||||
createRoutesFromElements,
|
createRoutesFromElements,
|
||||||
RouterProvider,
|
RouterProvider,
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import Settings from './pages/settings/Settings';
|
import Settings from "./pages/settings/Settings";
|
||||||
import { ModalsProvider } from '@mantine/modals';
|
import { ModalsProvider } from "@mantine/modals";
|
||||||
import { useLocalStorage } from '@mantine/hooks';
|
import { useLocalStorage } from "@mantine/hooks";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import { useQueryAPI } from './hooks/useAPI';
|
import { useQueryAPI } from "./hooks/useAPI";
|
||||||
import ThemeProvider from './components/ThemeProvider';
|
import ThemeProvider from "./components/ThemeProvider";
|
||||||
import '@mantine/core/styles.css'; //import Mantine V7 styles needed by MRT
|
import "@mantine/core/styles.css"; //import Mantine V7 styles needed by MRT
|
||||||
import '@mantine/dates/styles.css'; //if using mantine date picker features
|
import "@mantine/dates/styles.css"; //if using mantine date picker features
|
||||||
import 'mantine-react-table/styles.css'; //import MRT styles
|
import "mantine-react-table/styles.css"; //import MRT styles
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const { data, isFetched } = useQueryAPI({
|
||||||
const { data, isFetched } = useQueryAPI({
|
|
||||||
endpoint: "api/themes",
|
endpoint: "api/themes",
|
||||||
});
|
});
|
||||||
|
|
||||||
const [themeName, setThemeName] = useLocalStorage<any>({
|
const [themeName, setThemeName] = useLocalStorage<any>({
|
||||||
key: 'theme',
|
key: "theme",
|
||||||
defaultValue: 'blackboard',
|
defaultValue: "blackboard",
|
||||||
});
|
});
|
||||||
|
|
||||||
const [currentTheme, setCurrentTheme] = useState<any>({});
|
const [currentTheme, setCurrentTheme] = useState<any>({});
|
||||||
|
|
||||||
const overrides = createTheme({
|
const overrides = createTheme({
|
||||||
white:currentTheme.colorbackground,
|
white: currentTheme.colorbackground,
|
||||||
fontFamily: '-apple-system,Jost,BlinkMacSystemFont,Helvetica Neue,Roboto,sans-serif',
|
fontFamily:
|
||||||
});
|
"-apple-system,Jost,BlinkMacSystemFont,Helvetica Neue,Roboto,sans-serif",
|
||||||
|
});
|
||||||
|
|
||||||
const mantineTheme = mergeMantineTheme(DEFAULT_THEME, overrides);
|
const mantineTheme = mergeMantineTheme(DEFAULT_THEME, overrides);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(data && themeName) {
|
if (data && themeName) {
|
||||||
let temp = data.find((t: any) => t.name === themeName)
|
const temp = data.find((t: any) => t.name === themeName);
|
||||||
setCurrentTheme(temp);
|
setCurrentTheme(temp);
|
||||||
}
|
}
|
||||||
}, [isFetched, themeName])
|
}, [isFetched, themeName]);
|
||||||
|
|
||||||
const router = createBrowserRouter(
|
const router = createBrowserRouter(
|
||||||
createRoutesFromElements(
|
createRoutesFromElements(
|
||||||
<Route>
|
<Route>
|
||||||
<Route path="/trigger" element={<Homepage theme={currentTheme} />} />
|
<Route path="/trigger" element={<Homepage theme={currentTheme} />} />
|
||||||
<Route path="/trigger/settings" element={<Settings theme={currentTheme}/>} />
|
<Route
|
||||||
|
path="/trigger/settings"
|
||||||
|
element={<Settings theme={currentTheme} />}
|
||||||
|
/>
|
||||||
</Route>,
|
</Route>,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineProvider theme={mantineTheme}>
|
<MantineProvider theme={mantineTheme}>
|
||||||
<ThemeProvider theme={currentTheme}>
|
{currentTheme && (
|
||||||
<ModalsProvider>
|
<ThemeProvider theme={currentTheme}>
|
||||||
<RouterProvider router={router} />
|
<ModalsProvider>
|
||||||
</ModalsProvider>
|
<RouterProvider router={router} />
|
||||||
</ThemeProvider>
|
</ModalsProvider>
|
||||||
</MantineProvider>
|
</ThemeProvider>
|
||||||
)
|
)}
|
||||||
|
</MantineProvider>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App;
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { MantineReactTable, useMantineReactTable } from "mantine-react-table"
|
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
|
import "../dataTableStyles.css";
|
||||||
|
|
||||||
export function DataTableComponent({
|
export function DataTableComponent({
|
||||||
columns,
|
columns,
|
||||||
tableData,
|
tableData,
|
||||||
isFetching,
|
isFetching,
|
||||||
isLoading,
|
isLoading,
|
||||||
onCreatingRowSave,
|
onCreatingRowSave,
|
||||||
onEditingRowSave,
|
onEditingRowSave,
|
||||||
}: any) {
|
}: any) {
|
||||||
|
const table = useMantineReactTable({
|
||||||
const table = useMantineReactTable({
|
columns: columns,
|
||||||
columns: columns,
|
|
||||||
data: tableData,
|
data: tableData,
|
||||||
enableFacetedValues: true,
|
enableFacetedValues: true,
|
||||||
enablePagination: false,
|
enablePagination: false,
|
||||||
@@ -34,59 +34,23 @@ export function DataTableComponent({
|
|||||||
showLoadingOverlay: isLoading,
|
showLoadingOverlay: isLoading,
|
||||||
isLoading: isLoading,
|
isLoading: isLoading,
|
||||||
},
|
},
|
||||||
// mantineToolbarAlertBannerBadgeProps: {
|
mantineTableHeadProps: {
|
||||||
// style: {
|
style: {
|
||||||
// color: "red",
|
color: "var(--color-text-pri)",
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// mantineTopToolbarProps: {
|
mantineTableBodyCellProps: {
|
||||||
// style: {
|
style: {
|
||||||
// color: "var(--color-text-pri)",
|
color: "var(--color-text-pri)",
|
||||||
// background: "var(--color-background)",
|
background: "var(--color-background)",
|
||||||
// border: "none",
|
borderRight: "none",
|
||||||
// boxShadow: "none",
|
borderLeft: "none",
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// mantineTableHeadProps: {
|
|
||||||
// style: {
|
|
||||||
// boxShadow: "none",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// mantineTableHeadCellProps: {
|
|
||||||
// style: {
|
|
||||||
// color: "var(--color-text-pri)",
|
|
||||||
// background: "var(--color-background)",
|
|
||||||
// borderRight: "none",
|
|
||||||
// borderLeft: "none",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// mantineTableBodyCellProps: {
|
|
||||||
// style: {
|
|
||||||
// background: "var(--color-background)",
|
|
||||||
// borderRight: "none",
|
|
||||||
// borderLeft: "none",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// mantinePaperProps: {
|
|
||||||
// style: {
|
|
||||||
// border: "none",
|
|
||||||
// boxShadow: "none",
|
|
||||||
// background: "var(--color-background)",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// mantineTableContainerProps: {
|
|
||||||
// style: {
|
|
||||||
// border: "none",
|
|
||||||
// boxShadow: "none",
|
|
||||||
// background: "var(--color-background)",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
});
|
});
|
||||||
return (
|
return <MantineReactTable table={table} />;
|
||||||
<MantineReactTable table={table} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DataTable = memo(DataTableComponent);
|
export const DataTable = memo(DataTableComponent);
|
||||||
|
|
||||||
export default DataTable;
|
export default DataTable;
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { MRT_ColumnDef } from "mantine-react-table";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export default function ApplicationColumns() {
|
export default function ApplicationColumns() {
|
||||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
return `${row.id}`;
|
return `${row.id}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
enableEditing: false,
|
enableEditing: false,
|
||||||
id: "id",
|
id: "id",
|
||||||
@@ -27,7 +27,7 @@ export default function ApplicationColumns() {
|
|||||||
if (row.name) {
|
if (row.name) {
|
||||||
return `${row.name}`;
|
return `${row.name}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "name",
|
id: "name",
|
||||||
header: "Name",
|
header: "Name",
|
||||||
@@ -43,7 +43,7 @@ export default function ApplicationColumns() {
|
|||||||
if (row.url) {
|
if (row.url) {
|
||||||
return `${row.url}`;
|
return `${row.url}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "url",
|
id: "url",
|
||||||
header: "Url",
|
header: "Url",
|
||||||
@@ -59,7 +59,7 @@ export default function ApplicationColumns() {
|
|||||||
if (row.icon) {
|
if (row.icon) {
|
||||||
return `${row.icon}`;
|
return `${row.icon}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "icon",
|
id: "icon",
|
||||||
header: "Icon",
|
header: "Icon",
|
||||||
@@ -75,7 +75,7 @@ export default function ApplicationColumns() {
|
|||||||
if (row.urlbase) {
|
if (row.urlbase) {
|
||||||
return `${row.urlbase}`;
|
return `${row.urlbase}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "urlbase",
|
id: "urlbase",
|
||||||
header: "Base Url",
|
header: "Base Url",
|
||||||
@@ -91,7 +91,7 @@ export default function ApplicationColumns() {
|
|||||||
if (row.category) {
|
if (row.category) {
|
||||||
return `${row.category}`;
|
return `${row.category}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "category",
|
id: "category",
|
||||||
header: "Category",
|
header: "Category",
|
||||||
@@ -106,6 +106,5 @@ export default function ApplicationColumns() {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { MRT_ColumnDef } from "mantine-react-table";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export default function ApplicationColumns(groups: any, groupData: any) {
|
export default function ApplicationColumns(groups: any, groupData: any) {
|
||||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
return `${row.id}`;
|
return `${row.id}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
enableEditing: false,
|
enableEditing: false,
|
||||||
id: "id",
|
id: "id",
|
||||||
@@ -27,7 +27,7 @@ export default function ApplicationColumns(groups: any, groupData: any) {
|
|||||||
if (row.name) {
|
if (row.name) {
|
||||||
return `${row.name}`;
|
return `${row.name}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "name",
|
id: "name",
|
||||||
header: "Name",
|
header: "Name",
|
||||||
@@ -43,7 +43,7 @@ export default function ApplicationColumns(groups: any, groupData: any) {
|
|||||||
if (row.url) {
|
if (row.url) {
|
||||||
return `${row.url}`;
|
return `${row.url}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "url",
|
id: "url",
|
||||||
header: "Url",
|
header: "Url",
|
||||||
@@ -60,7 +60,7 @@ export default function ApplicationColumns(groups: any, groupData: any) {
|
|||||||
if (index !== null && index !== undefined) {
|
if (index !== null && index !== undefined) {
|
||||||
return `${index}`;
|
return `${index}`;
|
||||||
}
|
}
|
||||||
return "N/A";
|
return "N/A";
|
||||||
},
|
},
|
||||||
id: "category",
|
id: "category",
|
||||||
header: "Category",
|
header: "Category",
|
||||||
@@ -78,6 +78,5 @@ export default function ApplicationColumns(groups: any, groupData: any) {
|
|||||||
[groups],
|
[groups],
|
||||||
);
|
);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { MRT_ColumnDef } from "mantine-react-table";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export default function CategoryColumns() {
|
export default function CategoryColumns() {
|
||||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
return `${row.id}`;
|
return `${row.id}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
enableEditing: false,
|
enableEditing: false,
|
||||||
id: "id",
|
id: "id",
|
||||||
@@ -18,12 +18,12 @@ export default function CategoryColumns() {
|
|||||||
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
||||||
Header: ({ column }) => column.columnDef.header,
|
Header: ({ column }) => column.columnDef.header,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.category_name) {
|
if (row.category_name) {
|
||||||
return `${row.category_name}`;
|
return `${row.category_name}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "category_name",
|
id: "category_name",
|
||||||
header: "Name",
|
header: "Name",
|
||||||
@@ -31,12 +31,12 @@ export default function CategoryColumns() {
|
|||||||
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
||||||
Header: ({ column }) => column.columnDef.header,
|
Header: ({ column }) => column.columnDef.header,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.category_index > -1) {
|
if (row.category_index > -1) {
|
||||||
return `${row.category_index}`;
|
return `${row.category_index}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
enableEditing: false,
|
enableEditing: false,
|
||||||
id: "category_index",
|
id: "category_index",
|
||||||
@@ -45,12 +45,12 @@ export default function CategoryColumns() {
|
|||||||
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
||||||
Header: ({ column }) => column.columnDef.header,
|
Header: ({ column }) => column.columnDef.header,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.column_filter) {
|
if (row.column_filter) {
|
||||||
return `${row.column_filter}`;
|
return `${row.column_filter}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "column_filter",
|
id: "column_filter",
|
||||||
header: "Filter Name",
|
header: "Filter Name",
|
||||||
@@ -62,6 +62,5 @@ export default function CategoryColumns() {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { MRT_ColumnDef } from "mantine-react-table";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export default function MessagesColumns() {
|
export default function MessagesColumns() {
|
||||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
return `${row.id}`;
|
return `${row.id}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
enableEditing: false,
|
enableEditing: false,
|
||||||
id: "id",
|
id: "id",
|
||||||
@@ -27,7 +27,7 @@ export default function MessagesColumns() {
|
|||||||
if (row.message) {
|
if (row.message) {
|
||||||
return `${row.message}`;
|
return `${row.message}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "message",
|
id: "message",
|
||||||
header: "Message",
|
header: "Message",
|
||||||
@@ -43,7 +43,7 @@ export default function MessagesColumns() {
|
|||||||
if (row.easteregg) {
|
if (row.easteregg) {
|
||||||
return `${row.easteregg}`;
|
return `${row.easteregg}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "easteregg",
|
id: "easteregg",
|
||||||
header: "Easter Egg?",
|
header: "Easter Egg?",
|
||||||
@@ -58,6 +58,5 @@ export default function MessagesColumns() {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,61 +2,60 @@ import type { MRT_ColumnDef } from "mantine-react-table";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export default function PersonalizationColumns() {
|
export default function PersonalizationColumns() {
|
||||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorFn: (row: any) => {
|
accessorFn: (row: any) => {
|
||||||
if (row.firstname) {
|
if (row.firstname) {
|
||||||
return `${row.firstname}`;
|
return `${row.firstname}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "firstname",
|
id: "firstname",
|
||||||
header: "First Name",
|
header: "First Name",
|
||||||
size: 50,
|
size: 50,
|
||||||
mantineCopyButtonProps: ({ cell, row }) => ({
|
mantineCopyButtonProps: ({ cell, row }) => ({
|
||||||
className: "firstname",
|
className: "firstname",
|
||||||
id: `${cell.getValue()}-firstname`,
|
id: `${cell.getValue()}-firstname`,
|
||||||
}),
|
}),
|
||||||
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
||||||
Header: ({ column }) => column.columnDef.header,
|
Header: ({ column }) => column.columnDef.header,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (row: any) => {
|
accessorFn: (row: any) => {
|
||||||
if (row.lastname) {
|
if (row.lastname) {
|
||||||
return `${row.lastname}`;
|
return `${row.lastname}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "lastname",
|
id: "lastname",
|
||||||
header: "Last Name",
|
header: "Last Name",
|
||||||
mantineCopyButtonProps: ({ cell, row }) => ({
|
mantineCopyButtonProps: ({ cell, row }) => ({
|
||||||
className: "lastname",
|
className: "lastname",
|
||||||
id: `${cell.getValue()}-lastname`,
|
id: `${cell.getValue()}-lastname`,
|
||||||
}),
|
}),
|
||||||
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
||||||
Header: ({ column }) => column.columnDef.header,
|
Header: ({ column }) => column.columnDef.header,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (row: any) => {
|
accessorFn: (row: any) => {
|
||||||
if (row.email) {
|
if (row.email) {
|
||||||
return `${row.email}`;
|
return `${row.email}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "email",
|
id: "email",
|
||||||
header: "Email",
|
header: "Email",
|
||||||
mantineCopyButtonProps: ({ cell, row }) => ({
|
mantineCopyButtonProps: ({ cell, row }) => ({
|
||||||
className: "email",
|
className: "email",
|
||||||
id: `${cell.getValue()}-email`,
|
id: `${cell.getValue()}-email`,
|
||||||
}),
|
}),
|
||||||
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
Cell: ({ renderedCellValue, row }) => renderedCellValue,
|
||||||
Header: ({ column }) => column.columnDef.header,
|
Header: ({ column }) => column.columnDef.header,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import type { MRT_ColumnDef } from "mantine-react-table";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export default function SearchProviderColumns() {
|
export default function SearchProviderColumns() {
|
||||||
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
const columns = useMemo<MRT_ColumnDef<any>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorFn: (row) => {
|
accessorFn: (row) => {
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
return `${row.id}`;
|
return `${row.id}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
enableEditing: false,
|
enableEditing: false,
|
||||||
id: "id",
|
id: "id",
|
||||||
@@ -23,7 +23,7 @@ export default function SearchProviderColumns() {
|
|||||||
if (row.name) {
|
if (row.name) {
|
||||||
return `${row.name}`;
|
return `${row.name}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "name",
|
id: "name",
|
||||||
header: "Name",
|
header: "Name",
|
||||||
@@ -35,7 +35,7 @@ export default function SearchProviderColumns() {
|
|||||||
if (row.url) {
|
if (row.url) {
|
||||||
return `${row.url}`;
|
return `${row.url}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "url",
|
id: "url",
|
||||||
header: "Url",
|
header: "Url",
|
||||||
@@ -47,7 +47,7 @@ export default function SearchProviderColumns() {
|
|||||||
if (row.prefix) {
|
if (row.prefix) {
|
||||||
return `${row.prefix}`;
|
return `${row.prefix}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
id: "prefix",
|
id: "prefix",
|
||||||
header: "Prefix",
|
header: "Prefix",
|
||||||
@@ -58,6 +58,5 @@ export default function SearchProviderColumns() {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
import { Box } from '@mantine/core';
|
import { Box } from "@mantine/core";
|
||||||
|
|
||||||
export default function ThemeProvider({ theme, children }: { theme: any, children: React.ReactNode }) {
|
export default function ThemeProvider({
|
||||||
return <Box style={{
|
theme,
|
||||||
'--color-text-pri': theme.colortextpri,
|
children,
|
||||||
'--color-text-acc': theme.colortextacc,
|
}: { theme: any; children: React.ReactNode }) {
|
||||||
'--color-background': theme.colorbackground,
|
return (
|
||||||
'--color-border': theme.colorborder,
|
<Box
|
||||||
'--color-search-background': theme.colorsearchbackground,
|
style={{
|
||||||
}}>{children}</Box>;
|
"--color-text-pri": theme.colortextpri,
|
||||||
}
|
"--color-text-acc": theme.colortextacc,
|
||||||
|
"--color-background": theme.colorbackground,
|
||||||
|
"--color-border": theme.colorborder,
|
||||||
|
"--color-search-background": theme.colorsearchbackground,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from "@mantine/core";
|
||||||
import { stackClasses } from '../styles';
|
import { stackClasses } from "../styles";
|
||||||
|
|
||||||
export function ToastError({ err }: { err: any }) {
|
export function ToastError({ err }: { err: any }) {
|
||||||
const errorResponse = JSON.parse(err.message);
|
const errorResponse = JSON.parse(err.message);
|
||||||
return (
|
return (
|
||||||
<Stack className={stackClasses.VStack} style={{ alignItems: 'flex-start' }}>
|
<Stack className={stackClasses.VStack} style={{ alignItems: "flex-start" }}>
|
||||||
<Text>
|
<Text>
|
||||||
Status: {errorResponse.status} {errorResponse.statusText}
|
Status: {errorResponse.status} {errorResponse.statusText}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import { atom } from 'jotai';
|
import { atom } from "jotai";
|
||||||
|
|
||||||
export const HomepageFilters = atom([{value: 'All', label: 'All'}]);
|
export const HomepageFilters = atom([{ value: "All", label: "All" }]);
|
||||||
|
|||||||
@@ -1,173 +1,6 @@
|
|||||||
.mrt-table-paper {
|
|
||||||
height: 100%;
|
|
||||||
overflow: visible;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
border-style: none;
|
|
||||||
box-shadow: none;
|
|
||||||
&.mantine-Overlay-root {
|
|
||||||
color: var(--mantine-primary-color-7);
|
|
||||||
background-color: alpha(var(--mantine-color-appGray-9), 0.5);
|
|
||||||
}
|
|
||||||
&.mrt-toolbar-dropzone {
|
|
||||||
height: 4.5vh;
|
|
||||||
width: 35vw;
|
|
||||||
color: var(--mantine-primary-color-6);
|
|
||||||
font-size: 36px;
|
|
||||||
background-color: rgb(255, 255, 255, 1);
|
|
||||||
justify-self: center;
|
|
||||||
&.inner {
|
|
||||||
font-size: 36px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& ::-webkit-scrollbar {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
}
|
|
||||||
& ::-webkit-scrollbar-thumb:hover {
|
|
||||||
background-color: var(--mantine-primary-color-4);
|
|
||||||
}
|
|
||||||
& ::-webkit-scrollbar-track {
|
|
||||||
background-color: transparent;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
& ::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: var(--mantine-primary-color-6);
|
|
||||||
}
|
|
||||||
& ::-webkit-scrollbar-corner {
|
|
||||||
background-color: light-dark(white, var(--mantine-primary-color-8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mrt-table-container {
|
|
||||||
height: 100%;
|
|
||||||
background-color: light-dark(white, var(--mantine-primary-color-8));
|
|
||||||
border-top: solid;
|
|
||||||
border-top-color: light-dark(
|
|
||||||
var(--mantine-color-appGray-1),
|
|
||||||
var(--mantine-primary-color-6)
|
|
||||||
);
|
|
||||||
border-top-width: 1px;
|
|
||||||
border-left: solid;
|
|
||||||
border-left-color: light-dark(
|
|
||||||
var(--mantine-color-appGray-1),
|
|
||||||
var(--mantine-primary-color-6)
|
|
||||||
);
|
|
||||||
border-left-width: 1px;
|
|
||||||
border-right: solid;
|
|
||||||
border-right-color: light-dark(
|
|
||||||
var(--mantine-color-appGray-1),
|
|
||||||
var(--mantine-primary-color-6)
|
|
||||||
);
|
|
||||||
border-right-width: 1px;
|
|
||||||
border-bottom: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
border-bottom-left-radius: 0px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mantine-Table-th {
|
|
||||||
color: light-dark(var(--mantine-color-appGray-7), var(--mantine-primary-color-3));
|
|
||||||
background-color: light-dark(white, var(--mantine-primary-color-8));
|
|
||||||
border-color: light-dark(
|
|
||||||
var(--mantine-color-appGray-1),
|
|
||||||
var(--mantine-primary-color-7)
|
|
||||||
);
|
|
||||||
/* & .mantine-ActionIcon-root {
|
|
||||||
margin-right: 1px;
|
|
||||||
display: none;
|
|
||||||
} */
|
|
||||||
& .mrt-table-head-cell-content {
|
|
||||||
padding-top: 12px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
.mrt-table-head-cell-labels {
|
|
||||||
& > * > .mantine-Text-root {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .mrt-table-head-cell-content-actions {
|
|
||||||
transition: 1s all ease;
|
|
||||||
& .mantine-ActionIcon-root {
|
|
||||||
color: transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
display: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .mrt-table-head-cell-resize-handle {
|
|
||||||
display: flex;
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border-left-color: transparent;
|
|
||||||
background-color: light-dark(
|
|
||||||
var(--mantine-primary-color-1),
|
|
||||||
var(--mantine-primary-color-6)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
& .mantine-TableHeadCell-Content-Labels {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
& .mrt-table-head-cell-content-actions {
|
|
||||||
& .mantine-ActionIcon-root {
|
|
||||||
color: light-dark(var(--mantine-primary-color-6), var(--mantine-primary-color-3));
|
|
||||||
background-color: light-dark(
|
|
||||||
var(--mantine-primary-color-1),
|
|
||||||
var(--mantine-primary-color-6)
|
|
||||||
);
|
|
||||||
display: grid;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .mrt-table-head-cell-resize-handle {
|
|
||||||
border-left-color: var(--mantine-primary-color-2);
|
|
||||||
border-width: 4px;
|
|
||||||
border-left-style: solid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mantine-Mark-root {
|
|
||||||
background-color: light-dark(
|
|
||||||
var(--mantine-primary-color-7),
|
|
||||||
var(--mantine-primary-color-7)
|
|
||||||
);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mantine-Table-tr {
|
|
||||||
height: 56px;
|
|
||||||
box-shadow: none;
|
|
||||||
& .table-icon-device-floppy {
|
|
||||||
color: light-dark(var(--mantine-primary-color-6), var(--mantine-primary-color-3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mantine-Table-td {
|
|
||||||
color: light-dark(var(--mantine-color-appGray-7), var(--mantine-primary-color-3));
|
|
||||||
justify-content: center;
|
|
||||||
border-color: light-dark(
|
|
||||||
var(--mantine-color-appGray-1),
|
|
||||||
var(--mantine-primary-color-7)
|
|
||||||
);
|
|
||||||
|
|
||||||
& > * > .mantine-Text-root {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mrt-table-head-sort-button {
|
.mrt-table-head-sort-button {
|
||||||
display: none;
|
display: none;
|
||||||
|
color: var(--color-text-pri) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mrt-table-head-sort-button[data-sorted='asc'] {
|
.mrt-table-head-sort-button[data-sorted='asc'] {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { useQueryAPI } from './useAPI';
|
export { useQueryAPI } from "./useAPI";
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
import { useQuery, useQueryClient, useMutation, useInfiniteQuery } from '@tanstack/react-query';
|
import {
|
||||||
import { useCallback } from 'react';
|
useQuery,
|
||||||
import { toast } from 'react-toastify';
|
useQueryClient,
|
||||||
|
useMutation,
|
||||||
|
useInfiniteQuery,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export function useQueryAPI({ endpoint }: { endpoint: string }) {
|
export function useQueryAPI({ endpoint }: { endpoint: string }) {
|
||||||
|
|
||||||
const callEndpoint = async (endpoint: string) => {
|
const callEndpoint = async (endpoint: string) => {
|
||||||
const url = `http://localhost:5000/trigger/${endpoint}`;
|
const url = `http://localhost:5000/trigger/${endpoint}`;
|
||||||
const options: object = {
|
const options: object = {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
'Access-Control-Allow-Headers': '*',
|
"Access-Control-Allow-Headers": "*",
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
||||||
'Access-Control-Allow-Credentials': true,
|
"Access-Control-Allow-Credentials": true,
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
'Sec-Fetch-Site': 'same-site',
|
"Sec-Fetch-Site": "same-site",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,30 +31,28 @@ export function useQueryAPI({ endpoint }: { endpoint: string }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['GET', endpoint],
|
queryKey: ["GET", endpoint],
|
||||||
queryFn: () => callEndpoint(endpoint),
|
queryFn: () => callEndpoint(endpoint),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMutationAPI() {
|
export function useMutationAPI() {
|
||||||
|
|
||||||
const callEndpoint = async (
|
const callEndpoint = async (
|
||||||
method: string,
|
method: string,
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
body: object | undefined | null,
|
body: object | undefined | null,
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const url = `http://localhost:5000/trigger/${endpoint}`;
|
const url = `http://localhost:5000/trigger/${endpoint}`;
|
||||||
const options: any = {
|
const options: any = {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
'Access-Control-Allow-Headers': '*',
|
"Access-Control-Allow-Headers": "*",
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
||||||
'Access-Control-Allow-Credentials': true,
|
"Access-Control-Allow-Credentials": true,
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
'Sec-Fetch-Site': 'same-site'
|
"Sec-Fetch-Site": "same-site",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
};
|
};
|
||||||
@@ -58,7 +60,7 @@ export function useMutationAPI() {
|
|||||||
const response = await fetch(url, options);
|
const response = await fetch(url, options);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
if (typeof responseData.detail !== 'string') {
|
if (typeof responseData.detail !== "string") {
|
||||||
const errorResponse = JSON.stringify({
|
const errorResponse = JSON.stringify({
|
||||||
status: response.status,
|
status: response.status,
|
||||||
statusText: response.statusText,
|
statusText: response.statusText,
|
||||||
@@ -71,7 +73,7 @@ export function useMutationAPI() {
|
|||||||
|
|
||||||
throw new Error(errorResponse);
|
throw new Error(errorResponse);
|
||||||
}
|
}
|
||||||
if (typeof responseData.detail === 'object') {
|
if (typeof responseData.detail === "object") {
|
||||||
const errorResponse = JSON.stringify({
|
const errorResponse = JSON.stringify({
|
||||||
status: response.status,
|
status: response.status,
|
||||||
statusText: response.statusText,
|
statusText: response.statusText,
|
||||||
@@ -108,16 +110,18 @@ export function useMutationAPI() {
|
|||||||
}) => callEndpoint(method, endpoint, body),
|
}) => callEndpoint(method, endpoint, body),
|
||||||
onMutate: () => {},
|
onMutate: () => {},
|
||||||
onSuccess: (data, variables) => {
|
onSuccess: (data, variables) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', variables.endpoint] });
|
queryClient.invalidateQueries({ queryKey: ["GET", variables.endpoint] });
|
||||||
|
|
||||||
if (variables.endpoint.includes('/')) {
|
if (variables.endpoint.includes("/")) {
|
||||||
if ((variables.endpoint.match(/\//g) || []).length > 2) {
|
if ((variables.endpoint.match(/\//g) || []).length > 2) {
|
||||||
const GetEndpoint = variables.endpoint.split('/');
|
const GetEndpoint = variables.endpoint.split("/");
|
||||||
const Endpoint = `${GetEndpoint[1]}/${GetEndpoint[2]}`;
|
const Endpoint = `${GetEndpoint[1]}/${GetEndpoint[2]}`;
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', `/${Endpoint}`] });
|
queryClient.invalidateQueries({ queryKey: ["GET", `/${Endpoint}`] });
|
||||||
} else {
|
} else {
|
||||||
const GetEndpoint = variables.endpoint.split('/')[1];
|
const GetEndpoint = variables.endpoint.split("/")[1];
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', `/${GetEndpoint}`] });
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["GET", `/${GetEndpoint}`],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -125,32 +129,30 @@ export function useMutationAPI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useFileUploadAPI() {
|
export function useFileUploadAPI() {
|
||||||
|
|
||||||
const callEndpoint = async (
|
const callEndpoint = async (
|
||||||
method: string,
|
method: string,
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
body?: object | FormData | undefined | null,
|
body?: object | FormData | undefined | null,
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const url = `http://localhost:5000/trigger/${endpoint}`;
|
const url = `http://localhost:5000/trigger/${endpoint}`;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
'Access-Control-Allow-Headers': '*',
|
"Access-Control-Allow-Headers": "*",
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
||||||
'Access-Control-Allow-Credentials': true,
|
"Access-Control-Allow-Credentials": true,
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
'Sec-Fetch-Site': 'same-site',
|
"Sec-Fetch-Site": "same-site",
|
||||||
},
|
},
|
||||||
body: body ?? undefined,
|
body: body ?? undefined,
|
||||||
};
|
};
|
||||||
const response = await fetch(url, options as unknown as Body);
|
const response = await fetch(url, options as unknown as Body);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
if (typeof responseData.detail !== 'string') {
|
if (typeof responseData.detail !== "string") {
|
||||||
const errorResponse = JSON.stringify({
|
const errorResponse = JSON.stringify({
|
||||||
status: response.status,
|
status: response.status,
|
||||||
statusText: response.statusText,
|
statusText: response.statusText,
|
||||||
@@ -190,10 +192,10 @@ export function useFileUploadAPI() {
|
|||||||
}) => callEndpoint(method, endpoint, body),
|
}) => callEndpoint(method, endpoint, body),
|
||||||
onMutate: () => {},
|
onMutate: () => {},
|
||||||
onSuccess: (variables) => {
|
onSuccess: (variables) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', variables.endpoint] });
|
queryClient.invalidateQueries({ queryKey: ["GET", variables.endpoint] });
|
||||||
if (variables.endpoint?.includes('/')) {
|
if (variables.endpoint?.includes("/")) {
|
||||||
const GetEndpoint = variables.endpoint.split('/')[1];
|
const GetEndpoint = variables.endpoint.split("/")[1];
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', `/${GetEndpoint}`] });
|
queryClient.invalidateQueries({ queryKey: ["GET", `/${GetEndpoint}`] });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -204,12 +206,11 @@ export function useFetchAllRecordsAPI({ endpoint }: { endpoint: string }) {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const fetchPage = async (page: number, retryCount = 0): Promise<any> => {
|
const fetchPage = async (page: number, retryCount = 0): Promise<any> => {
|
||||||
|
|
||||||
// Start building the URL
|
// Start building the URL
|
||||||
const url = new URL(`http://localhost:5000/trigger/${endpoint}`);
|
const url = new URL(`http://localhost:5000/trigger/${endpoint}`);
|
||||||
|
|
||||||
// Check and append custom query parameters from the endpoint
|
// Check and append custom query parameters from the endpoint
|
||||||
const customParams = new URLSearchParams(endpoint.split('?')[1]);
|
const customParams = new URLSearchParams(endpoint.split("?")[1]);
|
||||||
for (const [key, value] of customParams) {
|
for (const [key, value] of customParams) {
|
||||||
if (!url.searchParams.has(key)) {
|
if (!url.searchParams.has(key)) {
|
||||||
url.searchParams.append(key, value);
|
url.searchParams.append(key, value);
|
||||||
@@ -217,19 +218,19 @@ export function useFetchAllRecordsAPI({ endpoint }: { endpoint: string }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add 'page' and 'size' parameters
|
// Add 'page' and 'size' parameters
|
||||||
url.searchParams.set('page', page.toString()); // Use 'set' to ensure uniqueness
|
url.searchParams.set("page", page.toString()); // Use 'set' to ensure uniqueness
|
||||||
url.searchParams.set('size', pageSize.toString());
|
url.searchParams.set("size", pageSize.toString());
|
||||||
|
|
||||||
const options: any = {
|
const options: any = {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
'Access-Control-Allow-Headers': '*',
|
"Access-Control-Allow-Headers": "*",
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
||||||
'Access-Control-Allow-Credentials': true,
|
"Access-Control-Allow-Credentials": true,
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
'Sec-Fetch-Site': 'same-site',
|
"Sec-Fetch-Site": "same-site",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -294,18 +295,18 @@ export function useFetchAllRecordsAPI({ endpoint }: { endpoint: string }) {
|
|||||||
return allItems;
|
return allItems;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handling errors in fetching the first page
|
// Handling errors in fetching the first page
|
||||||
console.error('Error fetching the first page:', error);
|
console.error("Error fetching the first page:", error);
|
||||||
return []; // Return empty array on error
|
return []; // Return empty array on error
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const invalidate = useCallback(() => {
|
const invalidate = useCallback(() => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', endpoint] });
|
queryClient.invalidateQueries({ queryKey: ["GET", endpoint] });
|
||||||
}, [queryClient, endpoint]);
|
}, [queryClient, endpoint]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...useQuery({
|
...useQuery({
|
||||||
queryKey: ['GET', endpoint],
|
queryKey: ["GET", endpoint],
|
||||||
queryFn: callEndpoint,
|
queryFn: callEndpoint,
|
||||||
}),
|
}),
|
||||||
invalidate,
|
invalidate,
|
||||||
@@ -322,31 +323,31 @@ export function useDownloadFile() {
|
|||||||
async ({ endpoint, file_name }: DownloadFileOptions) => {
|
async ({ endpoint, file_name }: DownloadFileOptions) => {
|
||||||
const url = `http://localhost:5000/trigger/${endpoint}`;
|
const url = `http://localhost:5000/trigger/${endpoint}`;
|
||||||
const options: any = {
|
const options: any = {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
'Access-Control-Allow-Headers': '*',
|
"Access-Control-Allow-Headers": "*",
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
||||||
'Access-Control-Allow-Credentials': true,
|
"Access-Control-Allow-Credentials": true,
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
'Sec-Fetch-Site': 'same-site',
|
"Sec-Fetch-Site": "same-site",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const toastID = toast.loading('Processing...');
|
const toastID = toast.loading("Processing...");
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, options);
|
const response = await fetch(url, options);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Network response was not ok');
|
throw new Error("Network response was not ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
if (blob.type === 'application/json') {
|
if (blob.type === "application/json") {
|
||||||
const blob_text = await blob.text();
|
const blob_text = await blob.text();
|
||||||
const cleaned_text = blob_text.replace(/"/g, '');
|
const cleaned_text = blob_text.replace(/"/g, "");
|
||||||
toast.update(toastID, {
|
toast.update(toastID, {
|
||||||
render: cleaned_text,
|
render: cleaned_text,
|
||||||
type: 'info',
|
type: "info",
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
closeButton: null,
|
closeButton: null,
|
||||||
@@ -354,11 +355,11 @@ export function useDownloadFile() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== "undefined") {
|
||||||
const blobURL = window.URL.createObjectURL(blob);
|
const blobURL = window.URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement("a");
|
||||||
|
|
||||||
a.style.display = 'none';
|
a.style.display = "none";
|
||||||
a.href = blobURL;
|
a.href = blobURL;
|
||||||
a.download = file_name;
|
a.download = file_name;
|
||||||
|
|
||||||
@@ -368,17 +369,17 @@ export function useDownloadFile() {
|
|||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
toast.update(toastID, {
|
toast.update(toastID, {
|
||||||
render: `${file_name} Downloaded`,
|
render: `${file_name} Downloaded`,
|
||||||
type: 'success',
|
type: "success",
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
closeButton: null,
|
closeButton: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Download failed:', error);
|
console.error("Download failed:", error);
|
||||||
toast.update(toastID, {
|
toast.update(toastID, {
|
||||||
render: `Error Downloading ${file_name}. Please try again.`,
|
render: `Error Downloading ${file_name}. Please try again.`,
|
||||||
type: 'error',
|
type: "error",
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
closeButton: null,
|
closeButton: null,
|
||||||
@@ -391,7 +392,6 @@ export function useDownloadFile() {
|
|||||||
return downloadFile;
|
return downloadFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const useFetchInfiniteQuery = ({
|
export const useFetchInfiniteQuery = ({
|
||||||
endpoint,
|
endpoint,
|
||||||
pageSize = 10,
|
pageSize = 10,
|
||||||
@@ -399,27 +399,27 @@ export const useFetchInfiniteQuery = ({
|
|||||||
endpoint: string;
|
endpoint: string;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const queryKey = ['GET', endpoint];
|
const queryKey = ["GET", endpoint];
|
||||||
|
|
||||||
const fetchInfiniteQuery = async (endpoint: string) => {
|
const fetchInfiniteQuery = async (endpoint: string) => {
|
||||||
const url = `http://localhost:5000/trigger/${endpoint}`;
|
const url = `http://localhost:5000/trigger/${endpoint}`;
|
||||||
const requestOptions: any = {
|
const requestOptions: any = {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
'Access-Control-Allow-Headers': '*',
|
"Access-Control-Allow-Headers": "*",
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
||||||
'Access-Control-Allow-Credentials': true,
|
"Access-Control-Allow-Credentials": true,
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
'Sec-Fetch-Site': 'same-site'
|
"Sec-Fetch-Site": "same-site",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, requestOptions);
|
const response = await fetch(url, requestOptions);
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching transactions:', error);
|
console.error("Error fetching transactions:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -431,12 +431,25 @@ export const useFetchInfiniteQuery = ({
|
|||||||
}
|
}
|
||||||
return allPages.length + 1;
|
return allPages.length + 1;
|
||||||
};
|
};
|
||||||
const { data, isLoading, isFetchingNextPage, fetchNextPage, isError, isFetching } =
|
const {
|
||||||
useInfiniteQuery({
|
data,
|
||||||
queryKey,
|
isLoading,
|
||||||
queryFn,
|
isFetchingNextPage,
|
||||||
getNextPageParam,
|
fetchNextPage,
|
||||||
initialPageParam: 1,
|
isError,
|
||||||
});
|
isFetching,
|
||||||
return { data, isLoading, isFetchingNextPage, fetchNextPage, isError, isFetching };
|
} = useInfiniteQuery({
|
||||||
};
|
queryKey,
|
||||||
|
queryFn,
|
||||||
|
getNextPageParam,
|
||||||
|
initialPageParam: 1,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
isFetchingNextPage,
|
||||||
|
fetchNextPage,
|
||||||
|
isError,
|
||||||
|
isFetching,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
35
src/main.tsx
35
src/main.tsx
@@ -1,22 +1,21 @@
|
|||||||
import React from 'react'
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from "react-dom/client";
|
||||||
import App from './App.tsx'
|
import App from "./App.tsx";
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
gcTime: 1000 * 60 * 60 * 24, // 24 hours
|
gcTime: 1000 * 60 * 60 * 24, // 24 hours
|
||||||
staleTime: 1000 * 60 * 1, // 1 min
|
staleTime: 1000 * 60 * 1, // 1 min
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||||
|
<React.StrictMode>
|
||||||
<React.StrictMode>
|
<QueryClientProvider client={queryClient}>
|
||||||
<QueryClientProvider client={queryClient}>
|
<App />
|
||||||
<App />
|
</QueryClientProvider>
|
||||||
</QueryClientProvider>
|
</React.StrictMode>,
|
||||||
</React.StrictMode>,
|
);
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
import { Stack } from '@mantine/core';
|
import { Stack } from "@mantine/core";
|
||||||
import stackClasses from '../../styles/Stack.module.css';
|
import stackClasses from "../../styles/Stack.module.css";
|
||||||
import {useQueryAPI} from '../../hooks/useAPI';
|
import { useQueryAPI } from "../../hooks/useAPI";
|
||||||
import Search from './components/Search';
|
import Search from "./components/Search";
|
||||||
import Header from './components/Header';
|
import Header from "./components/Header";
|
||||||
import Applications from './components/Applications';
|
import Applications from "./components/Applications";
|
||||||
import Bookmarks from './components/Bookmarks';
|
import Bookmarks from "./components/Bookmarks";
|
||||||
import SettingsButton from './components/SettingsButton';
|
import SettingsButton from "./components/SettingsButton";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import '../../index.css';
|
import "../../index.css";
|
||||||
import { useLocalStorage } from '@mantine/hooks';
|
import { useLocalStorage } from "@mantine/hooks";
|
||||||
|
|
||||||
export default function Homepage({theme}:any) {
|
export default function Homepage({ theme }: any) {
|
||||||
const { data, isFetching } = useQueryAPI({ endpoint: 'api/messages' });
|
const { data, isFetching } = useQueryAPI({ endpoint: "api/messages" });
|
||||||
const [displayedGreeting, setDisplayedGreeting] = useState('');
|
const [displayedGreeting, setDisplayedGreeting] = useState("");
|
||||||
const [contentType, setContentType] = useLocalStorage<any>({ key: 'contenttype', defaultValue: 'All' });
|
const [contentType, setContentType] = useLocalStorage<any>({
|
||||||
|
key: "contenttype",
|
||||||
|
defaultValue: "All",
|
||||||
|
});
|
||||||
function date() {
|
function date() {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const dateOptions: Intl.DateTimeFormatOptions = {
|
const dateOptions: Intl.DateTimeFormatOptions = {
|
||||||
weekday: 'long',
|
weekday: "long",
|
||||||
year: 'numeric',
|
year: "numeric",
|
||||||
month: 'long',
|
month: "long",
|
||||||
day: 'numeric',
|
day: "numeric",
|
||||||
};
|
};
|
||||||
const date = currentDate.toLocaleDateString('en-GB', dateOptions);
|
const date = currentDate.toLocaleDateString("en-GB", dateOptions);
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
function greet(list: any) {
|
function greet(list: any) {
|
||||||
@@ -32,7 +35,7 @@ export default function Homepage({theme}:any) {
|
|||||||
let timeBased: any = [];
|
let timeBased: any = [];
|
||||||
let easterEggs: any = [];
|
let easterEggs: any = [];
|
||||||
for (const l of list) {
|
for (const l of list) {
|
||||||
if (l.easteregg === 'N') {
|
if (l.easteregg === "N") {
|
||||||
timeBased = timeBased.concat(l);
|
timeBased = timeBased.concat(l);
|
||||||
} else {
|
} else {
|
||||||
easterEggs = easterEggs.concat(l);
|
easterEggs = easterEggs.concat(l);
|
||||||
@@ -51,12 +54,16 @@ export default function Homepage({theme}:any) {
|
|||||||
}, [isFetching]);
|
}, [isFetching]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap={0} className={stackClasses.containerStack} justify='center'>
|
<Stack gap={0} className={stackClasses.containerStack} justify="center">
|
||||||
<Search />
|
<Search />
|
||||||
<Header date={date()} greet={displayedGreeting} />
|
<Header date={date()} greet={displayedGreeting} />
|
||||||
<Applications contentType={contentType}/>
|
<Applications contentType={contentType} />
|
||||||
<Bookmarks contentType={contentType}/>
|
<Bookmarks contentType={contentType} />
|
||||||
<SettingsButton theme={theme} contentType={contentType} setContentType={setContentType}/>
|
<SettingsButton
|
||||||
|
theme={theme}
|
||||||
|
contentType={contentType}
|
||||||
|
setContentType={setContentType}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,43 @@
|
|||||||
import { Icon } from '@iconify/react';
|
import { Icon } from "@iconify/react";
|
||||||
import { Box, Stack, Text } from '@mantine/core';
|
import { Box, Stack, Text } from "@mantine/core";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import stacks from '../../../styles/Stack.module.css';
|
import stacks from "../../../styles/Stack.module.css";
|
||||||
import texts from '../../../styles/Text.module.css';
|
import texts from "../../../styles/Text.module.css";
|
||||||
|
|
||||||
function AppItem({ url, icon, name }: any) {
|
function AppItem({ url, icon, name }: any) {
|
||||||
const [textDecoration, setTextDecoration] = useState<string>('none');
|
const [textDecoration, setTextDecoration] = useState<string>("none");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
component='a'
|
component="a"
|
||||||
href={`https://${url}`}
|
href={`https://${url}`}
|
||||||
onMouseOver={() => setTextDecoration('underline')}
|
onMouseOver={() => setTextDecoration("underline")}
|
||||||
onMouseOut={() => setTextDecoration('none')}
|
onMouseOut={() => setTextDecoration("none")}
|
||||||
className={stacks.appItemBox}
|
className={stacks.appItemBox}
|
||||||
>
|
>
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
height: '64px',
|
height: "64px",
|
||||||
marginRight: '1em',
|
marginRight: "1em",
|
||||||
marginLeft: '1em',
|
marginLeft: "1em",
|
||||||
paddingTop: '15px',
|
paddingTop: "15px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon icon={`mdi:${icon}`} height={32} width={32} />
|
<Icon icon={`mdi:${icon}`} height={32} width={32} />
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
gap: 0,
|
gap: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text className={texts.appName} classNames={texts}>{name}</Text>
|
<Text className={texts.appName} classNames={texts}>
|
||||||
|
{name}
|
||||||
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
className={texts.appUrl}
|
className={texts.appUrl}
|
||||||
classNames={texts}
|
classNames={texts}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from "@mantine/core";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import {useQueryAPI} from '../../../hooks/useAPI';
|
import { useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import texts from '../../../styles/Text.module.css';
|
import texts from "../../../styles/Text.module.css";
|
||||||
import AppItem from './AppItem';
|
import AppItem from "./AppItem";
|
||||||
|
|
||||||
function Applications({contentType}: any) {
|
function Applications({ contentType }: any) {
|
||||||
const { data, isFetching } = useQueryAPI({ endpoint: 'api/apps' });
|
const { data, isFetching } = useQueryAPI({ endpoint: "api/apps" });
|
||||||
const [applications, setApplications] = useState([]);
|
const [applications, setApplications] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFetching) {
|
if (!isFetching) {
|
||||||
@@ -13,24 +13,26 @@ function Applications({contentType}: any) {
|
|||||||
}
|
}
|
||||||
}, [isFetching]);
|
}, [isFetching]);
|
||||||
return (
|
return (
|
||||||
<Stack id='apps' style={{ gap: 0 }}>
|
<Stack id="apps" style={{ gap: 0 }}>
|
||||||
<Text className={texts.sectionTitle} classNames={texts}>Applications</Text>
|
<Text className={texts.sectionTitle} classNames={texts}>
|
||||||
|
Applications
|
||||||
|
</Text>
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
background: 'var(--color-background)',
|
background: "var(--color-background)",
|
||||||
gap: '.25rem',
|
gap: ".25rem",
|
||||||
backgroundSize: 'cover',
|
backgroundSize: "cover",
|
||||||
borderBottom: '0px solid',
|
borderBottom: "0px solid",
|
||||||
display: 'grid',
|
display: "grid",
|
||||||
gridColumnGap: '5px',
|
gridColumnGap: "5px",
|
||||||
gridRowGap: '5px',
|
gridRowGap: "5px",
|
||||||
gridTemplateColumns: '1fr 1fr 1fr 1fr 1fr 1fr',
|
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr 1fr",
|
||||||
gridTemplateRows: '64px',
|
gridTemplateRows: "64px",
|
||||||
paddingBottom: 'var(--module-spacing)',
|
paddingBottom: "var(--module-spacing)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{applications?.map((item: any) => {
|
{applications?.map((item: any) => {
|
||||||
if (item.category === contentType || contentType === 'All')
|
if (item.category === contentType || contentType === "All")
|
||||||
return (
|
return (
|
||||||
<AppItem
|
<AppItem
|
||||||
key={item.name}
|
key={item.name}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import BookmarkDetails from './BookmarkDetails';
|
|
||||||
|
|
||||||
function BookmarkGroups(props) {
|
|
||||||
const links = props.links;
|
|
||||||
return (
|
|
||||||
<div id='bookmarkForm'>
|
|
||||||
<h3>{links?.category}</h3>
|
|
||||||
{links?.map((links) => (
|
|
||||||
<BookmarkDetails key={links.name} name={links.name} url={links.url} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BookmarkGroups;
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from "@mantine/core";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import {useQueryAPI} from '../../../hooks/useAPI';
|
import { useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import texts from '../../../styles/Text.module.css';
|
import texts from "../../../styles/Text.module.css";
|
||||||
import LinkGroups from './LinkGroups';
|
import LinkGroups from "./LinkGroups";
|
||||||
|
|
||||||
function Links({contentType}: any) {
|
function Links({ contentType }: any) {
|
||||||
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
|
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
|
||||||
endpoint: 'api/links',
|
endpoint: "api/links",
|
||||||
});
|
});
|
||||||
const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({
|
const { data: groupData, isFetched: groupsIsFetched } = useQueryAPI({
|
||||||
endpoint: 'api/categories',
|
endpoint: "api/categories",
|
||||||
});
|
});
|
||||||
const [bookmarks, setBookmarks] = useState([]);
|
const [bookmarks, setBookmarks] = useState([]);
|
||||||
const [categories, setCategories] = useState([]);
|
const [categories, setCategories] = useState([]);
|
||||||
@@ -24,29 +24,32 @@ function Links({contentType}: any) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{groupsIsFetched && linksIsFetched && categories?.length > 0 && (
|
{groupsIsFetched && linksIsFetched && categories?.length > 0 && (
|
||||||
<Stack id='links' style={{ gap: 0 }}>
|
<Stack id="links" style={{ gap: 0 }}>
|
||||||
<Text className={texts.sectionTitle} classNames={texts}>Bookmarks</Text>
|
<Text className={texts.sectionTitle} classNames={texts}>
|
||||||
|
Bookmarks
|
||||||
|
</Text>
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
display: 'grid',
|
display: "grid",
|
||||||
flexWrap: 'nowrap',
|
flexWrap: "nowrap",
|
||||||
gridColumnGap: '20px',
|
gridColumnGap: "20px",
|
||||||
gridRowGap: '0px',
|
gridRowGap: "0px",
|
||||||
gridTemplateColumns: '1fr 1fr 1fr 1fr 1fr',
|
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr",
|
||||||
gridTemplateRows: 'auto',
|
gridTemplateRows: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{categories.map((category: any) => {
|
{categories.map((category: any) => {
|
||||||
if (
|
if (
|
||||||
category.column_filter === contentType ||
|
category.column_filter === contentType ||
|
||||||
contentType === 'All'
|
contentType === "All"
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<LinkGroups
|
<LinkGroups
|
||||||
key={category.id}
|
key={category.id}
|
||||||
category={category.category_name}
|
category={category.category_name}
|
||||||
links={bookmarks.filter(
|
links={bookmarks.filter(
|
||||||
(bookmark: any) => bookmark.category === category.category_index,
|
(bookmark: any) =>
|
||||||
|
bookmark.category === category.category_index,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from "@mantine/core";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import {textClasses} from '../../../styles';
|
import { textClasses } from "../../../styles";
|
||||||
|
|
||||||
function Header({ greet, date }: any) {
|
function Header({ greet, date }: any) {
|
||||||
const [time, setTime] = useState(new Date());
|
const [time, setTime] = useState(new Date());
|
||||||
@@ -22,50 +22,56 @@ function Header({ greet, date }: any) {
|
|||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
borderBottom: '0px solid',
|
borderBottom: "0px solid",
|
||||||
zIndex: '1',
|
zIndex: "1",
|
||||||
clear: 'both',
|
clear: "both",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'row',
|
flexDirection: "row",
|
||||||
gap: 0,
|
gap: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
display: 'grid',
|
display: "grid",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text className={textClasses.greeting} classNames={textClasses}>{greet}</Text>
|
<Text className={textClasses.greeting} classNames={textClasses}>
|
||||||
|
{greet}
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
float: 'right',
|
float: "right",
|
||||||
justifyContent: 'right',
|
justifyContent: "right",
|
||||||
width: 'auto',
|
width: "auto",
|
||||||
gap: 0,
|
gap: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text className={textClasses.dateTime} classNames={textClasses} style={{ width: 'max-content' }}>
|
<Text
|
||||||
|
className={textClasses.dateTime}
|
||||||
|
classNames={textClasses}
|
||||||
|
style={{ width: "max-content" }}
|
||||||
|
>
|
||||||
{date}
|
{date}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
component='h2'
|
component="h2"
|
||||||
className={textClasses.dateTime}
|
className={textClasses.dateTime}
|
||||||
classNames={textClasses}
|
classNames={textClasses}
|
||||||
style={{
|
style={{
|
||||||
justifyContent: 'right',
|
justifyContent: "right",
|
||||||
display: 'grid',
|
display: "grid",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{`${
|
{`${
|
||||||
time.getHours() === 0
|
time.getHours() === 0
|
||||||
? 12
|
? 12
|
||||||
: time.getHours() > 12
|
: time.getHours() > 12
|
||||||
? time.getHours() - 12
|
? time.getHours() - 12
|
||||||
: time.getHours()
|
: time.getHours()
|
||||||
}:${fixDigits(time.getMinutes())} ${time.getHours() >= 12 ? 'PM' : 'AM'}`}
|
}:${fixDigits(time.getMinutes())} ${time.getHours() >= 12 ? "PM" : "AM"}`}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from "@mantine/core";
|
||||||
import texts from '../../../styles/Text.module.css';
|
import texts from "../../../styles/Text.module.css";
|
||||||
import LinkItem from './LinkItem';
|
import LinkItem from "./LinkItem";
|
||||||
|
|
||||||
function LinkGroups({ links, category }: any) {
|
function LinkGroups({ links, category }: any) {
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
marginBottom: '0em',
|
marginBottom: "0em",
|
||||||
display: 'block',
|
display: "block",
|
||||||
lineHeight: '1.5rem',
|
lineHeight: "1.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text className={texts.linkCategory} classNames={texts}>{category}</Text>
|
<Text className={texts.linkCategory} classNames={texts}>
|
||||||
|
{category}
|
||||||
|
</Text>
|
||||||
{links?.map((link: any) => (
|
{links?.map((link: any) => (
|
||||||
<LinkItem key={link.name} link={link} />
|
<LinkItem key={link.name} link={link} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import { Text } from '@mantine/core';
|
import { Text } from "@mantine/core";
|
||||||
import texts from '../../../styles/Text.module.css';
|
import texts from "../../../styles/Text.module.css";
|
||||||
|
|
||||||
function LinkItem({ link }: any) {
|
function LinkItem({ link }: any) {
|
||||||
return (
|
return (
|
||||||
<Text className={texts.linkItem} classNames={texts} component='a' href={link.url}>
|
<Text
|
||||||
|
className={texts.linkItem}
|
||||||
|
classNames={texts}
|
||||||
|
component="a"
|
||||||
|
href={link.url}
|
||||||
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import Messages from '../../../components/Messages';
|
import Messages from "../../../components/Messages";
|
||||||
import useQueryAPI from '../../../hooks/useAPI';
|
import useQueryAPI from "../../../hooks/useAPI";
|
||||||
|
|
||||||
function MessageInfo() {
|
function MessageInfo() {
|
||||||
const messageData = useQueryAPI({ endpoint: 'api/messages' });
|
const messageData = useQueryAPI({ endpoint: "api/messages" });
|
||||||
const [greetings, setGreetings] = useState([]);
|
const [greetings, setGreetings] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -15,7 +15,7 @@ function MessageInfo() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{greetings && (
|
{greetings && (
|
||||||
<div id='messageForm'>
|
<div id="messageForm">
|
||||||
{greetings.map((greeting, index) => (
|
{greetings.map((greeting, index) => (
|
||||||
<Messages
|
<Messages
|
||||||
key={greeting.id}
|
key={greeting.id}
|
||||||
|
|||||||
@@ -4,72 +4,85 @@ import { useQueryAPI } from "../../../hooks";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function Search() {
|
export default function Search() {
|
||||||
const { data: providers } = useQueryAPI({ endpoint: 'api/providers' });
|
const { data: providers } = useQueryAPI({ endpoint: "api/providers" });
|
||||||
|
|
||||||
const [providerLabel, setProviderLabel] = useState('Google Search');
|
const [providerLabel, setProviderLabel] = useState("Google Search");
|
||||||
const [providerURL, setProviderURL] = useState('https://www.google.com/search?q=');
|
const [providerURL, setProviderURL] = useState(
|
||||||
|
"https://www.google.com/search?q=",
|
||||||
const handleKeyPress = (item: any) => {
|
);
|
||||||
const option = item.target.value.substr(1, item.target.value.indexOf(' ') - 1) || item.target.value.substr(1);
|
|
||||||
const subtext = item.target.value.substr(2 + option.length);
|
|
||||||
if (item.key === 'Enter') {
|
|
||||||
if (item.target.value.startsWith('/')) {
|
|
||||||
open(`${providerURL}${subtext}`, '_self');
|
|
||||||
} else if (validURL(item.target.value)) {
|
|
||||||
if (containsProtocol(item.target.value)) window.location = item.target.value;
|
|
||||||
else open(`https://${item.target.value}`, '_self');
|
|
||||||
} else {
|
|
||||||
open(`${providerURL}${subtext}`, '_self');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validURL(str: any) {
|
const handleKeyPress = (item: any) => {
|
||||||
const pattern = new RegExp(
|
const option =
|
||||||
'^(https?:\\/\\/)?' + // protocol
|
item.target.value.substr(1, item.target.value.indexOf(" ") - 1) ||
|
||||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
item.target.value.substr(1);
|
||||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
const subtext = item.target.value.substr(2 + option.length);
|
||||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
if (item.key === "Enter") {
|
||||||
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
if (item.target.value.startsWith("/")) {
|
||||||
'(\\#[-a-z\\d_]*)?$',
|
open(`${providerURL}${subtext}`, "_self");
|
||||||
'i',
|
} else if (validURL(item.target.value)) {
|
||||||
); // fragment locator
|
if (containsProtocol(item.target.value))
|
||||||
return !!pattern.test(str);
|
window.location = item.target.value;
|
||||||
}
|
else open(`https://${item.target.value}`, "_self");
|
||||||
function containsProtocol(str: any) {
|
} else {
|
||||||
const pattern = /^(https?:\/\/){1}.*/i;
|
open(`${providerURL}${subtext}`, "_self");
|
||||||
return !!pattern.test(str);
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
function validURL(str: any) {
|
||||||
|
const pattern = new RegExp(
|
||||||
|
"^(https?:\\/\\/)?" + // protocol
|
||||||
|
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
|
||||||
|
"((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
|
||||||
|
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
|
||||||
|
"(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
|
||||||
|
"(\\#[-a-z\\d_]*)?$",
|
||||||
|
"i",
|
||||||
|
); // fragment locator
|
||||||
|
return !!pattern.test(str);
|
||||||
|
}
|
||||||
|
function containsProtocol(str: any) {
|
||||||
|
const pattern = /^(https?:\/\/){1}.*/i;
|
||||||
|
return !!pattern.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: "transparent",
|
||||||
textAlign: 'center',
|
textAlign: "center",
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
padding: '.3em',
|
padding: ".3em",
|
||||||
display: 'inline-block',
|
display: "inline-block",
|
||||||
gap: 0,
|
gap: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
className={textInputClasses.search}
|
className={textInputClasses.search}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
spellCheck='true'
|
spellCheck="true"
|
||||||
leftSection={providerLabel}
|
leftSection={providerLabel}
|
||||||
onChange={(item: any) => {
|
onChange={(item: any) => {
|
||||||
if(item.target.value.startsWith('/')) {
|
if (item.target.value.startsWith("/")) {
|
||||||
setProviderLabel(providers?.find((p: any) => p.prefix === item.target.value.split(' ')[0]).name);
|
setProviderLabel(
|
||||||
setProviderURL(providers?.find((p: any) => p.prefix === item.target.value.split(' ')[0]).url);
|
providers?.find(
|
||||||
} else {
|
(p: any) => p.prefix === item.target.value.split(" ")[0],
|
||||||
setProviderLabel('Google Search');
|
).name,
|
||||||
setProviderURL('https://www.google.com/search?q=');
|
);
|
||||||
}
|
setProviderURL(
|
||||||
}}
|
providers?.find(
|
||||||
onKeyUp={(item: any) => {
|
(p: any) => p.prefix === item.target.value.split(" ")[0],
|
||||||
handleKeyPress(item);
|
).url,
|
||||||
}}
|
);
|
||||||
|
} else {
|
||||||
|
setProviderLabel("Google Search");
|
||||||
|
setProviderURL("https://www.google.com/search?q=");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onKeyUp={(item: any) => {
|
||||||
|
handleKeyPress(item);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
import { Button, Menu, NavLink, Select } from '@mantine/core';
|
import { Button, Menu, NavLink, Select } from "@mantine/core";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import { FiMenu, FiMonitor } from 'react-icons/fi';
|
import { FiMenu, FiMonitor } from "react-icons/fi";
|
||||||
import {useQueryAPI} from '../../../hooks/useAPI';
|
import { useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import button from '../../../styles/Button.module.css';
|
import button from "../../../styles/Button.module.css";
|
||||||
import menu from '../../../styles/Menu.module.css';
|
import menu from "../../../styles/Menu.module.css";
|
||||||
import navLink from '../../../styles/NavLink.module.css';
|
import navLink from "../../../styles/NavLink.module.css";
|
||||||
import selectClasses from '../../../styles/Select.module.css';
|
import selectClasses from "../../../styles/Select.module.css";
|
||||||
|
|
||||||
|
function SettingsButton({ contentType, setContentType, theme }: any) {
|
||||||
|
const { data, isFetched } = useQueryAPI({ endpoint: "api/appCategories" });
|
||||||
|
const [categories, setCategories] = useState([
|
||||||
|
{ value: "All", label: "All" },
|
||||||
|
]);
|
||||||
|
|
||||||
function SettingsButton({contentType, setContentType, theme}: any) {
|
|
||||||
const { data, isFetched } = useQueryAPI({ endpoint: 'api/appCategories' });
|
|
||||||
const [categories, setCategories] = useState([{value: 'All', label: 'All'}]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(data) {
|
if (data) {
|
||||||
const list: [any] = data.map((category: any) => {return {value: category.category, label: category.category}}) || [];
|
const list: [any] =
|
||||||
list.unshift({value: 'All', label: 'All'});
|
data.map((category: any) => {
|
||||||
|
return { value: category.category, label: category.category };
|
||||||
|
}) || [];
|
||||||
|
list.unshift({ value: "All", label: "All" });
|
||||||
setCategories(list);
|
setCategories(list);
|
||||||
}
|
}
|
||||||
}, [data, isFetched]);
|
}, [data, isFetched]);
|
||||||
|
|
||||||
function runWakeCommand() {
|
function runWakeCommand() {
|
||||||
const requestOptions = {
|
const requestOptions = {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { "Content-Type": "application/json" },
|
||||||
};
|
};
|
||||||
fetch('/trigger/api/wakeDakota', requestOptions);
|
fetch("/trigger/api/wakeDakota", requestOptions);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu withinPortal={false} withArrow shadow="md" position="top">
|
||||||
withinPortal={false}
|
|
||||||
withArrow
|
|
||||||
shadow='md'
|
|
||||||
position='top'
|
|
||||||
>
|
|
||||||
<Menu.Target>
|
<Menu.Target>
|
||||||
<Button className={button.settingsButton} classNames={button}>
|
<Button className={button.settingsButton} classNames={button}>
|
||||||
<FiMenu />
|
<FiMenu />
|
||||||
</Button>
|
</Button>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown
|
<Menu.Dropdown className={menu.dropdown}>
|
||||||
className={menu.dropdown}
|
|
||||||
>
|
|
||||||
<NavLink
|
<NavLink
|
||||||
label='Settings'
|
label="Settings"
|
||||||
component='a'
|
component="a"
|
||||||
href='/trigger/settings'
|
href="/trigger/settings"
|
||||||
className={navLink.defaultNavLink}
|
className={navLink.defaultNavLink}
|
||||||
classNames={navLink}
|
classNames={navLink}
|
||||||
/>
|
/>
|
||||||
<NavLink label='Quick Actions'
|
<NavLink
|
||||||
|
label="Quick Actions"
|
||||||
className={navLink.defaultNavLink}
|
className={navLink.defaultNavLink}
|
||||||
classNames={navLink}>
|
classNames={navLink}
|
||||||
|
>
|
||||||
<NavLink
|
<NavLink
|
||||||
label='Wake Dakota'
|
label="Wake Dakota"
|
||||||
leftSection={<FiMonitor />}
|
leftSection={<FiMonitor />}
|
||||||
onClick={() => runWakeCommand()}
|
onClick={() => runWakeCommand()}
|
||||||
className={navLink.defaultNavLink}
|
className={navLink.defaultNavLink}
|
||||||
@@ -60,12 +60,12 @@ function SettingsButton({contentType, setContentType, theme}: any) {
|
|||||||
/>
|
/>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<Select
|
<Select
|
||||||
label='Homepage Filter'
|
label="Homepage Filter"
|
||||||
data={categories ?? []}
|
data={categories ?? []}
|
||||||
defaultValue={contentType}
|
defaultValue={contentType}
|
||||||
withCheckIcon={false}
|
withCheckIcon={false}
|
||||||
onChange={(data: any) => {
|
onChange={(data: any) => {
|
||||||
setContentType(data)
|
setContentType(data);
|
||||||
}}
|
}}
|
||||||
classNames={selectClasses}
|
classNames={selectClasses}
|
||||||
comboboxProps={{ withinPortal: false }}
|
comboboxProps={{ withinPortal: false }}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ActionIcon, Group, Stack, Tabs } from "@mantine/core";
|
import { ActionIcon, Group, Stack, Tabs, Text } from "@mantine/core";
|
||||||
import tabClasses from '../../styles/Tabs.module.css';
|
import tabClasses from "../../styles/Tabs.module.css";
|
||||||
import Personalization from "./components/Personalization";
|
import Personalization from "./components/Personalization";
|
||||||
import { FiArrowLeftCircle } from "react-icons/fi";
|
import { FiArrowLeftCircle } from "react-icons/fi";
|
||||||
import { actionIconClasses } from "../../styles";
|
import { actionIconClasses, textClasses } from "../../styles";
|
||||||
import Messages from "./components/Messages";
|
import Messages from "./components/Messages";
|
||||||
import Applications from "./components/Applications";
|
import Applications from "./components/Applications";
|
||||||
import Bookmarks from "./components/Bookmarks";
|
import Bookmarks from "./components/Bookmarks";
|
||||||
@@ -10,32 +10,60 @@ import Categories from "./components/Categories";
|
|||||||
import SearchProviders from "./components/SearchProviders";
|
import SearchProviders from "./components/SearchProviders";
|
||||||
import Themes from "./components/Themes";
|
import Themes from "./components/Themes";
|
||||||
|
|
||||||
function Settings({theme}:any) {
|
function Settings({ theme }: any) {
|
||||||
return (
|
return (
|
||||||
<Stack h={'100vh'} px={'2rem'} bg={'var(--color-background)'}>
|
<Stack h={"100vh"} px={"2rem"} bg={"var(--color-background)"}>
|
||||||
<Group gap={0} >
|
<Group gap={0}>
|
||||||
<ActionIcon className={actionIconClasses.backButton} classNames={actionIconClasses} component="a" href="/trigger"><FiArrowLeftCircle/></ActionIcon>
|
<ActionIcon
|
||||||
<h1>Settings</h1>
|
className={actionIconClasses.backButton}
|
||||||
</Group>
|
classNames={actionIconClasses}
|
||||||
<Tabs orientation="vertical" defaultValue={'personalization'} className={tabClasses.settingsTabs} classNames={tabClasses}>
|
component="a"
|
||||||
<Tabs.List>
|
href="/trigger"
|
||||||
<Tabs.Tab value="personalization">Personal Info</Tabs.Tab>
|
>
|
||||||
<Tabs.Tab value="messages">Messages</Tabs.Tab>
|
<FiArrowLeftCircle />
|
||||||
<Tabs.Tab value="applications">Applications</Tabs.Tab>
|
</ActionIcon>
|
||||||
<Tabs.Tab value="bookmarks">Bookmarks</Tabs.Tab>
|
<Text className={textClasses.settingsTitle} classNames={textClasses}>
|
||||||
<Tabs.Tab value="bookmarksCategories">Categories</Tabs.Tab>
|
Settings
|
||||||
<Tabs.Tab value="themes">Themes</Tabs.Tab>
|
</Text>
|
||||||
<Tabs.Tab value="providers">Search Providers</Tabs.Tab>
|
</Group>
|
||||||
</Tabs.List>
|
<Tabs
|
||||||
<Tabs.Panel value="personalization"><Personalization/></Tabs.Panel>
|
orientation="vertical"
|
||||||
<Tabs.Panel value="messages"><Messages/></Tabs.Panel>
|
defaultValue={"personalization"}
|
||||||
<Tabs.Panel value="applications"><Applications/></Tabs.Panel>
|
className={tabClasses.settingsTabs}
|
||||||
<Tabs.Panel value="bookmarks"><Bookmarks/></Tabs.Panel>
|
classNames={tabClasses}
|
||||||
<Tabs.Panel value="bookmarksCategories"><Categories/></Tabs.Panel>
|
>
|
||||||
<Tabs.Panel value="themes"><Themes/></Tabs.Panel>
|
<Tabs.List>
|
||||||
<Tabs.Panel value="providers"><SearchProviders/></Tabs.Panel>
|
<Tabs.Tab value="personalization">Personal Info</Tabs.Tab>
|
||||||
</Tabs>
|
<Tabs.Tab value="messages">Messages</Tabs.Tab>
|
||||||
</Stack>
|
<Tabs.Tab value="applications">Applications</Tabs.Tab>
|
||||||
|
<Tabs.Tab value="bookmarks">Bookmarks</Tabs.Tab>
|
||||||
|
<Tabs.Tab value="bookmarksCategories">Categories</Tabs.Tab>
|
||||||
|
<Tabs.Tab value="themes">Themes</Tabs.Tab>
|
||||||
|
<Tabs.Tab value="providers">Search Providers</Tabs.Tab>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Panel value="personalization">
|
||||||
|
<Personalization />
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="messages">
|
||||||
|
<Messages />
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="applications">
|
||||||
|
<Applications />
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="bookmarks">
|
||||||
|
<Bookmarks />
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="bookmarksCategories">
|
||||||
|
<Categories />
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="themes">
|
||||||
|
<Themes theme={theme} />
|
||||||
|
</Tabs.Panel>
|
||||||
|
<Tabs.Panel value="providers">
|
||||||
|
<SearchProviders />
|
||||||
|
</Tabs.Panel>
|
||||||
|
</Tabs>
|
||||||
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|||||||
@@ -1,59 +1,61 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
|
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { DataTable } from "../../../DataTable/DataTable";
|
import { DataTable } from "../../../DataTable/DataTable";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import type { MRT_TableOptions } from "mantine-react-table";
|
import type { MRT_TableOptions } from "mantine-react-table";
|
||||||
import ApplicationColumns from "../../../DataTable/columns/ApplicationColumns";
|
import ApplicationColumns from "../../../DataTable/columns/ApplicationColumns";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack, Text } from "@mantine/core";
|
||||||
|
import { textClasses } from "../../../styles";
|
||||||
const ApplicationSettings = () => {
|
const ApplicationSettings = () => {
|
||||||
const endpoint = "api/apps";
|
const endpoint = "api/apps";
|
||||||
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [applicationData, setApplicationData] = useState<any>([]);
|
const [applicationData, setApplicationData] = useState<any>([]);
|
||||||
|
|
||||||
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
|
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
|
||||||
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
|
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isFetched) {
|
if (isFetched) {
|
||||||
setApplicationData(data);
|
setApplicationData(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleCreateRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
values,
|
values,
|
||||||
exitCreatingMode,
|
exitCreatingMode,
|
||||||
}) => {
|
}) => {
|
||||||
|
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
|
||||||
createRow({method: "POST", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Application created successfully");
|
||||||
toast.success("Application created successfully");
|
});
|
||||||
})
|
exitCreatingMode();
|
||||||
exitCreatingMode();
|
};
|
||||||
};
|
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
const handleEditRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
values,
|
||||||
values,
|
table,
|
||||||
table,
|
}) => {
|
||||||
}) => {
|
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
|
||||||
editRow({method: "PATCH", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Application updated successfully");
|
||||||
toast.success("Application updated successfully");
|
});
|
||||||
});
|
table.setEditingRow(null);
|
||||||
table.setEditingRow(null);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<h2>Applications</h2>
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
<DataTable
|
Applications
|
||||||
tableName="Applications"
|
</Text>
|
||||||
columns={ApplicationColumns()}
|
<DataTable
|
||||||
tableData={applicationData}
|
tableName="Applications"
|
||||||
isFetching={isFetching}
|
columns={ApplicationColumns()}
|
||||||
isLoading={isLoading}
|
tableData={applicationData}
|
||||||
onCreatingRowSave={handleCreateRow}
|
isFetching={isFetching}
|
||||||
onEditingRowSave={handleEditRow}
|
isLoading={isLoading}
|
||||||
/>
|
onCreatingRowSave={handleCreateRow}
|
||||||
</Stack>
|
onEditingRowSave={handleEditRow}
|
||||||
)
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default ApplicationSettings;
|
export default ApplicationSettings;
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
|
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { DataTable } from "../../../DataTable/DataTable";
|
import { DataTable } from "../../../DataTable/DataTable";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import type { MRT_TableOptions } from "mantine-react-table";
|
import type { MRT_TableOptions } from "mantine-react-table";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack, Text } from "@mantine/core";
|
||||||
import BookmarkColumns from "../../../DataTable/columns/BookmarkColumns";
|
import BookmarkColumns from "../../../DataTable/columns/BookmarkColumns";
|
||||||
|
import { textClasses } from "../../../styles";
|
||||||
const BookmarkSettings = () => {
|
const BookmarkSettings = () => {
|
||||||
const endpoint = "api/links";
|
const endpoint = "api/links";
|
||||||
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
@@ -17,16 +18,16 @@ const BookmarkSettings = () => {
|
|||||||
isFetched: groupDataisFetched,
|
isFetched: groupDataisFetched,
|
||||||
} = useQueryAPI({ endpoint: "api/categories" });
|
} = useQueryAPI({ endpoint: "api/categories" });
|
||||||
const [bookmarkData, setBookmarkData] = useState<any>([]);
|
const [bookmarkData, setBookmarkData] = useState<any>([]);
|
||||||
const [groups, setGroups] = useState([]);
|
const [groups, setGroups] = useState([]);
|
||||||
const [fullyFetched, setFullyFetched] = useState(false);
|
const [fullyFetched, setFullyFetched] = useState(false);
|
||||||
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
|
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
|
||||||
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
|
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isFetched) {
|
if (isFetched) {
|
||||||
setBookmarkData(data);
|
setBookmarkData(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (groupDataisFetched) {
|
if (groupDataisFetched) {
|
||||||
@@ -38,39 +39,40 @@ const BookmarkSettings = () => {
|
|||||||
}
|
}
|
||||||
}, [groupDataisFetched]);
|
}, [groupDataisFetched]);
|
||||||
|
|
||||||
const handleCreateRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
values,
|
values,
|
||||||
exitCreatingMode,
|
exitCreatingMode,
|
||||||
}) => {
|
}) => {
|
||||||
|
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
|
||||||
createRow({method: "POST", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Application created successfully");
|
||||||
toast.success("Application created successfully");
|
});
|
||||||
})
|
exitCreatingMode();
|
||||||
exitCreatingMode();
|
};
|
||||||
};
|
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
const handleEditRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
values,
|
||||||
values,
|
table,
|
||||||
table,
|
}) => {
|
||||||
}) => {
|
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
|
||||||
editRow({method: "PATCH", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Application updated successfully");
|
||||||
toast.success("Application updated successfully");
|
});
|
||||||
});
|
table.setEditingRow(null);
|
||||||
table.setEditingRow(null);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<h2>Bookmarks</h2>
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
<DataTable
|
Bookmarks
|
||||||
tableName="Applications"
|
</Text>
|
||||||
columns={BookmarkColumns(groups, groupData)}
|
<DataTable
|
||||||
tableData={bookmarkData}
|
tableName="Applications"
|
||||||
isFetching={isFetching}
|
columns={BookmarkColumns(groups, groupData)}
|
||||||
isLoading={isLoading}
|
tableData={bookmarkData}
|
||||||
onCreatingRowSave={handleCreateRow}
|
isFetching={isFetching}
|
||||||
onEditingRowSave={handleEditRow}
|
isLoading={isLoading}
|
||||||
/>
|
onCreatingRowSave={handleCreateRow}
|
||||||
</Stack>
|
onEditingRowSave={handleEditRow}
|
||||||
)
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default BookmarkSettings;
|
export default BookmarkSettings;
|
||||||
|
|||||||
@@ -1,59 +1,61 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
|
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { DataTable } from "../../../DataTable/DataTable";
|
import { DataTable } from "../../../DataTable/DataTable";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import type { MRT_TableOptions } from "mantine-react-table";
|
import type { MRT_TableOptions } from "mantine-react-table";
|
||||||
import CategoryColumns from "../../../DataTable/columns/CategoryColumns";
|
import CategoryColumns from "../../../DataTable/columns/CategoryColumns";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack, Text } from "@mantine/core";
|
||||||
|
import { textClasses } from "../../../styles";
|
||||||
const CategorySettings = () => {
|
const CategorySettings = () => {
|
||||||
const endpoint = "api/categories";
|
const endpoint = "api/categories";
|
||||||
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [categoryData, setCategoryData] = useState<any>([]);
|
const [categoryData, setCategoryData] = useState<any>([]);
|
||||||
|
|
||||||
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
|
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
|
||||||
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
|
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isFetched) {
|
if (isFetched) {
|
||||||
setCategoryData(data);
|
setCategoryData(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleCreateRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
values,
|
values,
|
||||||
exitCreatingMode,
|
exitCreatingMode,
|
||||||
}) => {
|
}) => {
|
||||||
|
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
|
||||||
createRow({method: "POST", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Category created successfully");
|
||||||
toast.success("Category created successfully");
|
});
|
||||||
})
|
exitCreatingMode();
|
||||||
exitCreatingMode();
|
};
|
||||||
};
|
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
const handleEditRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
values,
|
||||||
values,
|
table,
|
||||||
table,
|
}) => {
|
||||||
}) => {
|
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
|
||||||
editRow({method: "PATCH", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Category updated successfully");
|
||||||
toast.success("Category updated successfully");
|
});
|
||||||
});
|
table.setEditingRow(null);
|
||||||
table.setEditingRow(null);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<h2>Categories</h2>
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
<DataTable
|
Categories
|
||||||
tableName="Categories"
|
</Text>
|
||||||
columns={CategoryColumns()}
|
<DataTable
|
||||||
tableData={categoryData}
|
tableName="Categories"
|
||||||
isFetching={isFetching}
|
columns={CategoryColumns()}
|
||||||
isLoading={isLoading}
|
tableData={categoryData}
|
||||||
onCreatingRowSave={handleCreateRow}
|
isFetching={isFetching}
|
||||||
onEditingRowSave={handleEditRow}
|
isLoading={isLoading}
|
||||||
/>
|
onCreatingRowSave={handleCreateRow}
|
||||||
</Stack>
|
onEditingRowSave={handleEditRow}
|
||||||
)
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default CategorySettings;
|
export default CategorySettings;
|
||||||
|
|||||||
@@ -1,59 +1,61 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
|
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { DataTable } from "../../../DataTable/DataTable";
|
import { DataTable } from "../../../DataTable/DataTable";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import type { MRT_TableOptions } from "mantine-react-table";
|
import type { MRT_TableOptions } from "mantine-react-table";
|
||||||
import MessagesColumns from "../../../DataTable/columns/MessagesColumns";
|
import MessagesColumns from "../../../DataTable/columns/MessagesColumns";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack, Text } from "@mantine/core";
|
||||||
|
import { textClasses } from "../../../styles";
|
||||||
const MessageSettings = () => {
|
const MessageSettings = () => {
|
||||||
const endpoint = "api/messages";
|
const endpoint = "api/messages";
|
||||||
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [messageData, setMessageData] = useState<any>([]);
|
const [messageData, setMessageData] = useState<any>([]);
|
||||||
|
|
||||||
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
|
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
|
||||||
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
|
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isFetched) {
|
if (isFetched) {
|
||||||
setMessageData(data);
|
setMessageData(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleCreateRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
values,
|
values,
|
||||||
exitCreatingMode,
|
exitCreatingMode,
|
||||||
}) => {
|
}) => {
|
||||||
|
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
|
||||||
createRow({method: "POST", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Message created successfully");
|
||||||
toast.success("Message created successfully");
|
});
|
||||||
})
|
exitCreatingMode();
|
||||||
exitCreatingMode();
|
};
|
||||||
};
|
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
const handleEditRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
values,
|
||||||
values,
|
table,
|
||||||
table,
|
}) => {
|
||||||
}) => {
|
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
|
||||||
editRow({method: "PATCH", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Message updated successfully");
|
||||||
toast.success("Message updated successfully");
|
});
|
||||||
});
|
table.setEditingRow(null);
|
||||||
table.setEditingRow(null);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<h2>Messages</h2>
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
<DataTable
|
Messages
|
||||||
tableName="Messages"
|
</Text>
|
||||||
columns={MessagesColumns()}
|
<DataTable
|
||||||
tableData={messageData}
|
tableName="Messages"
|
||||||
isFetching={isFetching}
|
columns={MessagesColumns()}
|
||||||
isLoading={isLoading}
|
tableData={messageData}
|
||||||
onCreatingRowSave={handleCreateRow}
|
isFetching={isFetching}
|
||||||
onEditingRowSave={handleEditRow}
|
isLoading={isLoading}
|
||||||
/>
|
onCreatingRowSave={handleCreateRow}
|
||||||
</Stack>
|
onEditingRowSave={handleEditRow}
|
||||||
)
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default MessageSettings;
|
export default MessageSettings;
|
||||||
|
|||||||
@@ -1,58 +1,61 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
|
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { DataTable } from "../../../DataTable/DataTable";
|
import { DataTable } from "../../../DataTable/DataTable";
|
||||||
import PersonalizationColumns from "../../../DataTable/columns/PersonalizationColumns";
|
import PersonalizationColumns from "../../../DataTable/columns/PersonalizationColumns";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import type { MRT_TableOptions } from "mantine-react-table";
|
import type { MRT_TableOptions } from "mantine-react-table";
|
||||||
|
import { textClasses } from "../../../styles";
|
||||||
|
import { Text } from "@mantine/core";
|
||||||
const PersonalizationSettings = () => {
|
const PersonalizationSettings = () => {
|
||||||
const endpoint = "api/personaldata";
|
const endpoint = "api/personaldata";
|
||||||
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [personalData, setPersonalData] = useState<any>([]);
|
const [personalData, setPersonalData] = useState<any>([]);
|
||||||
|
|
||||||
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
|
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
|
||||||
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
|
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isFetched) {
|
if (isFetched) {
|
||||||
setPersonalData(data);
|
setPersonalData(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleCreateRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
values,
|
values,
|
||||||
exitCreatingMode,
|
exitCreatingMode,
|
||||||
}) => {
|
}) => {
|
||||||
|
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
|
||||||
createRow({method: "POST", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Personalization created successfully");
|
||||||
toast.success("Personalization created successfully");
|
});
|
||||||
})
|
exitCreatingMode();
|
||||||
exitCreatingMode();
|
};
|
||||||
};
|
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
const handleEditRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
values,
|
||||||
values,
|
table,
|
||||||
table,
|
}) => {
|
||||||
}) => {
|
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
|
||||||
editRow({method: "PATCH", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Personalization updated successfully");
|
||||||
toast.success("Personalization updated successfully");
|
});
|
||||||
});
|
table.setEditingRow(null);
|
||||||
table.setEditingRow(null);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h2>Personalization</h2>
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
<DataTable
|
Personalization
|
||||||
tableName="Personalization"
|
</Text>
|
||||||
columns={PersonalizationColumns()}
|
<DataTable
|
||||||
tableData={personalData}
|
tableName="Personalization"
|
||||||
isFetching={isFetching}
|
columns={PersonalizationColumns()}
|
||||||
isLoading={isLoading}
|
tableData={personalData}
|
||||||
onCreatingRowSave={handleCreateRow}
|
isFetching={isFetching}
|
||||||
onEditingRowSave={handleEditRow}
|
isLoading={isLoading}
|
||||||
/>
|
onCreatingRowSave={handleCreateRow}
|
||||||
</>
|
onEditingRowSave={handleEditRow}
|
||||||
)
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default PersonalizationSettings;
|
export default PersonalizationSettings;
|
||||||
|
|||||||
@@ -1,59 +1,61 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {useMutationAPI, useQueryAPI} from "../../../hooks/useAPI";
|
import { useMutationAPI, useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { DataTable } from "../../../DataTable/DataTable";
|
import { DataTable } from "../../../DataTable/DataTable";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import type { MRT_TableOptions } from "mantine-react-table";
|
import type { MRT_TableOptions } from "mantine-react-table";
|
||||||
import SearchProviderColumns from "../../../DataTable/columns/SearchProviderColumns";
|
import SearchProviderColumns from "../../../DataTable/columns/SearchProviderColumns";
|
||||||
import { Stack } from "@mantine/core";
|
import { Stack, Text } from "@mantine/core";
|
||||||
|
import { textClasses } from "../../../styles";
|
||||||
const SearchProviderSettings = () => {
|
const SearchProviderSettings = () => {
|
||||||
const endpoint = "api/providers";
|
const endpoint = "api/providers";
|
||||||
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
const { data, isFetching, isLoading, isFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [providerData, setProviderData] = useState<any>([]);
|
const [providerData, setProviderData] = useState<any>([]);
|
||||||
|
|
||||||
const {mutateAsync: createRow, isPending: isCreatingRow} = useMutationAPI();
|
const { mutateAsync: createRow, isPending: isCreatingRow } = useMutationAPI();
|
||||||
const {mutateAsync: editRow, isPending: isEditingRow} = useMutationAPI();
|
const { mutateAsync: editRow, isPending: isEditingRow } = useMutationAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isFetched) {
|
if (isFetched) {
|
||||||
setProviderData(data);
|
setProviderData(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleCreateRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
const handleCreateRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
values,
|
values,
|
||||||
exitCreatingMode,
|
exitCreatingMode,
|
||||||
}) => {
|
}) => {
|
||||||
|
createRow({ method: "POST", endpoint: endpoint, body: values }).then(() => {
|
||||||
createRow({method: "POST", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Search provider created successfully");
|
||||||
toast.success("Search provider created successfully");
|
});
|
||||||
})
|
exitCreatingMode();
|
||||||
exitCreatingMode();
|
};
|
||||||
};
|
const handleEditRow: MRT_TableOptions<any>["onCreatingRowSave"] = async ({
|
||||||
const handleEditRow: MRT_TableOptions<any>['onCreatingRowSave'] = async ({
|
values,
|
||||||
values,
|
table,
|
||||||
table,
|
}) => {
|
||||||
}) => {
|
editRow({ method: "PATCH", endpoint: endpoint, body: values }).then(() => {
|
||||||
editRow({method: "PATCH", endpoint: endpoint, body: values}).then(() => {
|
toast.success("Search provider updated successfully");
|
||||||
toast.success("Search provider updated successfully");
|
});
|
||||||
});
|
table.setEditingRow(null);
|
||||||
table.setEditingRow(null);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<h2>Search Providers</h2>
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
<DataTable
|
Search Providers
|
||||||
tableName="Categories"
|
</Text>
|
||||||
columns={SearchProviderColumns()}
|
<DataTable
|
||||||
tableData={providerData}
|
tableName="Categories"
|
||||||
isFetching={isFetching}
|
columns={SearchProviderColumns()}
|
||||||
isLoading={isLoading}
|
tableData={providerData}
|
||||||
onCreatingRowSave={handleCreateRow}
|
isFetching={isFetching}
|
||||||
onEditingRowSave={handleEditRow}
|
isLoading={isLoading}
|
||||||
/>
|
onCreatingRowSave={handleCreateRow}
|
||||||
</Stack>
|
onEditingRowSave={handleEditRow}
|
||||||
)
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default SearchProviderSettings;
|
export default SearchProviderSettings;
|
||||||
|
|||||||
250
src/pages/settings/components/ThemeModalContent.tsx
Normal file
250
src/pages/settings/components/ThemeModalContent.tsx
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||||
|
import { Stack, Group, Text, Box } from "@mantine/core";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { stackClasses } from "../../../styles";
|
||||||
|
|
||||||
|
export default function ThemeModalContent({ selectedTheme }: any) {
|
||||||
|
const ExampleApp = (previewTheme: any) => {
|
||||||
|
const [textDecoration, setTextDecoration] = useState<string>("none");
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
component="a"
|
||||||
|
onMouseOver={() => setTextDecoration("underline")}
|
||||||
|
onMouseOut={() => setTextDecoration("none")}
|
||||||
|
className={stackClasses.appItemBox}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
height: "64px",
|
||||||
|
marginRight: "1em",
|
||||||
|
marginLeft: "1em",
|
||||||
|
paddingTop: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
style={{ color: previewTheme.theme.colortextpri }}
|
||||||
|
icon={`mdi:check`}
|
||||||
|
height={32}
|
||||||
|
width={32}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "center",
|
||||||
|
flex: 1,
|
||||||
|
overflow: "hidden",
|
||||||
|
gap: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: 11,
|
||||||
|
fontStyle: "normal",
|
||||||
|
color: previewTheme.theme.colortextpri,
|
||||||
|
fontFamily:
|
||||||
|
"-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important",
|
||||||
|
margin: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{"Example App"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: 11,
|
||||||
|
fontStyle: "italic",
|
||||||
|
color: previewTheme.theme.colortextacc,
|
||||||
|
fontFamily:
|
||||||
|
"-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important",
|
||||||
|
margin: 0,
|
||||||
|
textDecoration: textDecoration,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{"https://www.example.com"}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: selectedTheme.colorbackground,
|
||||||
|
borderRadius: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Group
|
||||||
|
justify="center"
|
||||||
|
style={{
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
paddingTop: "1rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedTheme.name}
|
||||||
|
</Group>
|
||||||
|
<Text
|
||||||
|
pl={"1.5rem"}
|
||||||
|
style={{
|
||||||
|
textDecoration: "underline",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 200,
|
||||||
|
fontStyle: "italic",
|
||||||
|
height: "10px",
|
||||||
|
textTransform: "uppercase",
|
||||||
|
marginTop: "20px",
|
||||||
|
marginBottom: "20px",
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Applications
|
||||||
|
</Text>
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
background: selectedTheme.colorbackground,
|
||||||
|
gap: ".25rem",
|
||||||
|
backgroundSize: "cover",
|
||||||
|
borderBottom: "0px solid",
|
||||||
|
display: "grid",
|
||||||
|
gridColumnGap: "5px",
|
||||||
|
gridRowGap: "5px",
|
||||||
|
gridTemplateColumns: "1fr 1fr 1fr",
|
||||||
|
gridTemplateRows: "64px",
|
||||||
|
padding: "1rem",
|
||||||
|
paddingTop: "0rem",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ExampleApp theme={selectedTheme} />
|
||||||
|
<ExampleApp theme={selectedTheme} />
|
||||||
|
<ExampleApp theme={selectedTheme} />
|
||||||
|
</Stack>
|
||||||
|
<Text
|
||||||
|
pl={"1.5rem"}
|
||||||
|
style={{
|
||||||
|
textDecoration: "underline",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 200,
|
||||||
|
fontStyle: "italic",
|
||||||
|
height: "10px",
|
||||||
|
textTransform: "uppercase",
|
||||||
|
marginTop: "20px",
|
||||||
|
marginBottom: "20px",
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Bookmarks
|
||||||
|
</Text>
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
flexWrap: "nowrap",
|
||||||
|
gridColumnGap: "20px",
|
||||||
|
gridRowGap: "0px",
|
||||||
|
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr",
|
||||||
|
gridTemplateRows: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
marginBottom: "0em",
|
||||||
|
display: "block",
|
||||||
|
lineHeight: "1.5rem",
|
||||||
|
padding: "1rem",
|
||||||
|
paddingTop: "0rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: 400,
|
||||||
|
height: "10px",
|
||||||
|
width: "auto",
|
||||||
|
color: selectedTheme.colortextacc,
|
||||||
|
textTransform: "uppercase",
|
||||||
|
marginTop: "20px",
|
||||||
|
marginBottom: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Example Category
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: 2,
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
}}
|
||||||
|
component="a"
|
||||||
|
>
|
||||||
|
{"Link 1"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: 2,
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
}}
|
||||||
|
component="a"
|
||||||
|
>
|
||||||
|
{"Link 2"}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
marginBottom: "0em",
|
||||||
|
display: "block",
|
||||||
|
lineHeight: "1.5rem",
|
||||||
|
padding: "1rem",
|
||||||
|
paddingTop: "0rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: "14px",
|
||||||
|
fontWeight: 400,
|
||||||
|
height: "10px",
|
||||||
|
width: "auto",
|
||||||
|
color: selectedTheme.colortextacc,
|
||||||
|
textTransform: "uppercase",
|
||||||
|
marginTop: "20px",
|
||||||
|
marginBottom: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Example Category
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: 2,
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
}}
|
||||||
|
component="a"
|
||||||
|
>
|
||||||
|
{"Link 1"}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: 2,
|
||||||
|
color: selectedTheme.colortextpri,
|
||||||
|
}}
|
||||||
|
component="a"
|
||||||
|
>
|
||||||
|
{"Link 2"}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,87 +1,160 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useQueryAPI } from "../../../hooks/useAPI";
|
import { useQueryAPI } from "../../../hooks/useAPI";
|
||||||
import { ActionIcon, Button, ColorPicker, ColorSwatch, Group, Modal, SimpleGrid, Stack } from "@mantine/core";
|
import {
|
||||||
import AppItem from "../../homepage/components/AppItem";
|
ActionIcon,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
ColorPicker,
|
||||||
|
ColorSwatch,
|
||||||
|
Divider,
|
||||||
|
Group,
|
||||||
|
Modal,
|
||||||
|
SimpleGrid,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
} from "@mantine/core";
|
||||||
import { FiEdit } from "react-icons/fi";
|
import { FiEdit } from "react-icons/fi";
|
||||||
import { useDisclosure, useLocalStorage } from "@mantine/hooks";
|
import { useDisclosure, useLocalStorage } from "@mantine/hooks";
|
||||||
import '@mantine/core/styles/ModalBase.css';
|
import "@mantine/core/styles/ModalBase.css";
|
||||||
import '@mantine/core/styles/Modal.css';
|
import "@mantine/core/styles/Modal.css";
|
||||||
function ThemesSettings() {
|
import { actionIconClasses, modalClasses, textClasses } from "../../../styles";
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
import ThemeModalContent from "./ThemeModalContent";
|
||||||
const [value, setValue] = useLocalStorage<any>({ key: 'theme', defaultValue: {} });
|
function ThemesSettings({ theme }: any) {
|
||||||
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
|
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
|
||||||
|
const [colorValue, onChange] = useState('#000000');
|
||||||
|
const [value, setValue] = useLocalStorage<any>({
|
||||||
|
key: "theme",
|
||||||
|
defaultValue: {},
|
||||||
|
});
|
||||||
const { data, isFetched } = useQueryAPI({
|
const { data, isFetched } = useQueryAPI({
|
||||||
endpoint: "api/themes",
|
endpoint: "api/themes",
|
||||||
});
|
});
|
||||||
const [themesList, setThemesList] = useState([]);
|
const [themesList, setThemesList] = useState([]);
|
||||||
const [selectedTheme, setSelectedTheme] = useState<any>({});
|
const [selectedTheme, setSelectedTheme] = useState<any>({});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFetched) {
|
if (isFetched) {
|
||||||
setThemesList(data);
|
setThemesList(data);
|
||||||
}
|
}
|
||||||
}, [isFetched]);
|
}, [isFetched]);
|
||||||
|
|
||||||
const handleOpen = (theme: any) => {
|
const handleOpen = (theme: any) => {
|
||||||
setSelectedTheme(theme);
|
setSelectedTheme(theme);
|
||||||
open();
|
open();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
close();
|
||||||
|
closePicker();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal.Root opened={opened} onClose={close}>
|
<Modal.Root
|
||||||
<Modal.Overlay />
|
size={"50%"}
|
||||||
<Modal.Content>
|
style={{
|
||||||
<Modal.Header>
|
"--color-text-pri": theme.colortextpri,
|
||||||
<Modal.Title>Edit Theme</Modal.Title>
|
"--color-text-acc": theme.colortextacc,
|
||||||
<Modal.CloseButton />
|
"--color-background": theme.colorbackground,
|
||||||
</Modal.Header>
|
"--color-border": theme.colorborder,
|
||||||
<Modal.Body>
|
"--color-search-background": theme.colorsearchbackground,
|
||||||
<Stack style={{ backgroundColor: selectedTheme.colorbackground, borderRadius: '10px' }}>
|
}}
|
||||||
<Group justify="center" style={{ color: selectedTheme.colortextpri }}>{selectedTheme.name}</Group>
|
className={modalClasses.editThemeModal}
|
||||||
<AppItem
|
classNames={modalClasses}
|
||||||
name={'Example App'}
|
opened={opened}
|
||||||
url={'https://example.com'}
|
onClose={handleClose}
|
||||||
icon={'mdi:apps'}
|
>
|
||||||
category={'Default'}
|
<Modal.Overlay />
|
||||||
/>
|
<Modal.Content>
|
||||||
</Stack>
|
<Modal.Header>
|
||||||
</Modal.Body>
|
<Modal.Title>Edit Theme</Modal.Title>
|
||||||
</Modal.Content>
|
<Modal.CloseButton />
|
||||||
</Modal.Root>
|
</Modal.Header>
|
||||||
<Stack h={'100%'} w={'100%'}>
|
<Modal.Body p={"2rem"}>
|
||||||
<h2>Themes</h2>
|
<ThemeModalContent selectedTheme={selectedTheme} />
|
||||||
<SimpleGrid cols={5}>
|
<Divider color="black" my="sm" />
|
||||||
{themesList.map((theme: any) => (
|
<Group w={"100%"} h={"100%"} gap={0}>
|
||||||
<Stack key={theme.name}>
|
<Stack w={"50%"}>
|
||||||
<Button
|
<Group c={'black'} justify="space-between">
|
||||||
style={{
|
<Text>Primary Color</Text>
|
||||||
backgroundColor: theme.colorbackground,
|
<ColorSwatch onClick={openPicker} radius={"sm"} w={"100px"} color={selectedTheme.colortextpri} />
|
||||||
border: `solid ${theme.colorborder}`,
|
|
||||||
color: theme.colortextpri,
|
|
||||||
}}
|
|
||||||
data-theme={theme.name}
|
|
||||||
onClick={() => {
|
|
||||||
setValue(theme.name)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{theme.name}
|
|
||||||
</Button>
|
|
||||||
<Group justify="space-between">
|
|
||||||
<Group className="theme-palette">
|
|
||||||
<ColorSwatch color={theme.colorbackground} />
|
|
||||||
<ColorSwatch color={theme.colorsearchbackground} />
|
|
||||||
<ColorSwatch color={theme.colortextpri} />
|
|
||||||
<ColorSwatch color={theme.colortextacc} />
|
|
||||||
<ColorSwatch color={theme.colorborder} />
|
|
||||||
</Group>
|
</Group>
|
||||||
<ActionIcon
|
<Group c={'black'} justify="space-between">
|
||||||
onClick={() => handleOpen(theme)}
|
<Text>Accent Color</Text>
|
||||||
><FiEdit/></ActionIcon>
|
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colortextacc} />
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
<Group c={'black'} justify="space-between">
|
||||||
))}
|
<Text>Background Color</Text>
|
||||||
</SimpleGrid>
|
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorbackground} />
|
||||||
</Stack>
|
</Group>
|
||||||
</>
|
<Group c={'black'} justify="space-between">
|
||||||
|
<Text>Border Color</Text>
|
||||||
|
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorborder} />
|
||||||
|
</Group>
|
||||||
|
<Group c={'black'} justify="space-between">
|
||||||
|
<Text>Search Background Color</Text>
|
||||||
|
<ColorSwatch radius={"sm"} w={"100px"} color={selectedTheme.colorsearchbackground} />
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
<Stack h={"100%"} w={'50%'} align="center" justify="center">
|
||||||
|
{pickerOpen ? (
|
||||||
|
<>
|
||||||
|
<ColorPicker value={colorValue} onChange={onChange}/>
|
||||||
|
<Group><Text c={'black'}>{colorValue}</Text><Button onClick={() => {setSelectedTheme({ ...selectedTheme, colorbackground: colorValue }); closePicker();}} c={'white'} bg={'forestgreen'}>Save</Button></Group>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Card bg={'#0002'} h={"100%"} w={"90%"}>
|
||||||
|
<Text c="black">
|
||||||
|
Pick a swatch to edit the color.
|
||||||
|
</Text>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Group>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal.Content>
|
||||||
|
</Modal.Root>
|
||||||
|
<Stack h={"100%"} w={"100%"}>
|
||||||
|
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
|
Themes
|
||||||
|
</Text>
|
||||||
|
<SimpleGrid cols={5}>
|
||||||
|
{themesList.map((theme: any) => (
|
||||||
|
<Stack key={theme.name}>
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme.colorbackground,
|
||||||
|
border: `solid ${theme.colorborder}`,
|
||||||
|
color: theme.colortextpri,
|
||||||
|
}}
|
||||||
|
data-theme={theme.name}
|
||||||
|
onClick={() => {
|
||||||
|
setValue(theme.name);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{theme.name}
|
||||||
|
</Button>
|
||||||
|
<Group justify="space-between">
|
||||||
|
<Group className="theme-palette">
|
||||||
|
<ColorSwatch color={theme.colorbackground} />
|
||||||
|
<ColorSwatch color={theme.colorsearchbackground} />
|
||||||
|
<ColorSwatch color={theme.colortextpri} />
|
||||||
|
<ColorSwatch color={theme.colortextacc} />
|
||||||
|
<ColorSwatch color={theme.colorborder} />
|
||||||
|
</Group>
|
||||||
|
<ActionIcon
|
||||||
|
className={actionIconClasses.editButton}
|
||||||
|
classNames={actionIconClasses}
|
||||||
|
onClick={() => handleOpen(theme)}
|
||||||
|
>
|
||||||
|
<FiEdit />
|
||||||
|
</ActionIcon>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default ThemesSettings;
|
export default ThemesSettings;
|
||||||
|
|||||||
@@ -1,12 +1,37 @@
|
|||||||
.backButton {
|
.backButton {
|
||||||
&.root {
|
&.root {
|
||||||
background-color: transparent;
|
background-color: transparent !important;
|
||||||
color: black;
|
color: var(--color-text-pri) !important;
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
|
margin-right: 1rem;
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
.loader {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
:hover {
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: var(--color-text-pri) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.editButton {
|
||||||
|
&.root {
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: var(--color-text-pri) !important;
|
||||||
|
.icon {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.loader {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
:hover {
|
||||||
|
background-color: var(--color-text-pri) !important;
|
||||||
|
color: var(--color-text-acc) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
27
src/styles/Modal.module.css
Normal file
27
src/styles/Modal.module.css
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
.editThemeModal {
|
||||||
|
.header {
|
||||||
|
color: white;
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
color: light-dark(var(--mantine-primary-color-6), white);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
.body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
color: var(--mantine-color-appRed-3);
|
||||||
|
background-color: var(--mantine-color-appRed-1);
|
||||||
|
max-width: 20px!important;
|
||||||
|
max-height: 20px!important;
|
||||||
|
&:hover {
|
||||||
|
color: var(--mantine-color-appRed-1);
|
||||||
|
background-color: var(--mantine-color-appRed-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,4 +3,11 @@
|
|||||||
padding-left: 2rem;
|
padding-left: 2rem;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
.tab {
|
||||||
|
color: var(--color-text-pri);
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-background);
|
||||||
|
background-color: var(--color-text-acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +86,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settingsTitle {
|
||||||
|
&.root {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
color: var(--color-text-pri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settingsSubTitle {
|
||||||
|
&.root {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
color: var(--color-text-pri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.settingsLink {
|
.settingsLink {
|
||||||
&.root {
|
&.root {
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
import actionIconClasses from './ActionIcon.module.css';
|
import actionIconClasses from "./ActionIcon.module.css";
|
||||||
import buttonClasses from './Button.module.css';
|
import buttonClasses from "./Button.module.css";
|
||||||
import menuClasses from './Menu.module.css';
|
import menuClasses from "./Menu.module.css";
|
||||||
import navLinkClasses from './NavLink.module.css';
|
import modalClasses from "./Modal.module.css";
|
||||||
import popoverClasses from './Popover.module.css';
|
import navLinkClasses from "./NavLink.module.css";
|
||||||
import selectClasses from './Select.module.css';
|
import popoverClasses from "./Popover.module.css";
|
||||||
import stackClasses from './Stack.module.css';
|
import selectClasses from "./Select.module.css";
|
||||||
import tabClasses from './Tabs.module.css';
|
import stackClasses from "./Stack.module.css";
|
||||||
import textClasses from './Text.module.css';
|
import tabClasses from "./Tabs.module.css";
|
||||||
import textInputClasses from './TextInput.module.css';
|
import textClasses from "./Text.module.css";
|
||||||
|
import textInputClasses from "./TextInput.module.css";
|
||||||
|
|
||||||
export { actionIconClasses, buttonClasses, menuClasses, navLinkClasses, popoverClasses, selectClasses, stackClasses, tabClasses, textClasses, textInputClasses }
|
export {
|
||||||
|
actionIconClasses,
|
||||||
|
buttonClasses,
|
||||||
|
menuClasses,
|
||||||
|
modalClasses,
|
||||||
|
navLinkClasses,
|
||||||
|
popoverClasses,
|
||||||
|
selectClasses,
|
||||||
|
stackClasses,
|
||||||
|
tabClasses,
|
||||||
|
textClasses,
|
||||||
|
textInputClasses,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strict": true
|
"strict": true
|
||||||
},
|
},
|
||||||
"include": ["vite.config.ts"]
|
"include": ["vite.config.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import react from '@vitejs/plugin-react';
|
import react from "@vitejs/plugin-react";
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
host: '0.0.0.0',
|
host: "0.0.0.0",
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
"/api": {
|
||||||
target: 'http://localhost:5000/trigger',
|
target: "http://localhost:5000/trigger",
|
||||||
changeOrigin: false,
|
changeOrigin: false,
|
||||||
secure: false,
|
secure: false,
|
||||||
},
|
},
|
||||||
@@ -17,13 +17,13 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
host: '0.0.0.0',
|
host: "0.0.0.0",
|
||||||
proxy: {
|
proxy: {
|
||||||
api: {
|
api: {
|
||||||
target: 'http://localhost:5000',
|
target: "http://localhost:5000",
|
||||||
changeOrigin: false,
|
changeOrigin: false,
|
||||||
secure: false,
|
secure: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user