Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
84f25fb
refactor: make email group dropdown UI consistent with rest of the dr…
DilhanRubera Jun 9, 2025
544eac2
feat : add module name in actions container
DilhanRubera Jun 18, 2025
29fda01
refactor : change secondary and background colors in theme palette
DilhanRubera Jun 18, 2025
4c61f7f
refactor : remove text transform of mui buttons globally
DilhanRubera Jun 18, 2025
a7dbfd0
refactor : change search bar styling
DilhanRubera Jun 18, 2025
eed78b4
feat : add custom filter
DilhanRubera Jun 18, 2025
127b2f9
refactor : change existing filter object type fields to implement new…
DilhanRubera Jun 18, 2025
7a89967
feat: add custom columns panel
DilhanRubera Jun 18, 2025
63b6f30
refactor: add needed props to implement custom columns panel in data …
DilhanRubera Jun 18, 2025
31011af
feat: add needed props, helper methods, implement customer filter and…
DilhanRubera Jun 18, 2025
e36bb42
refactor: add props to implement filter and columns panel and ui enha…
DilhanRubera Jun 18, 2025
c720d5f
fix: make data grid in data list horizontally scrollable
DilhanRubera Jun 18, 2025
0a34914
fix: display correct error message in login page
DilhanRubera Jun 20, 2025
dffac8f
refactor: remove module name from left corner
DilhanRubera Jun 20, 2025
3f31bcc
refactor: move searchbar to left side of the contacts page
DilhanRubera Jun 20, 2025
644a843
refactor: make searchbar wider
DilhanRubera Jun 20, 2025
c13bc07
refactor: change theme fonts, color palette and backgrounds
DilhanRubera Jun 26, 2025
9cabe66
refactor: change sidebar formatting
DilhanRubera Jun 26, 2025
927fc92
refactor: fix searchbar formatting
DilhanRubera Jun 26, 2025
419dc3b
refactor: fix contacts, datatable and module formatting
DilhanRubera Jun 26, 2025
b7a5b98
feat: add responsive actions component to dynamically resize itself b…
DilhanRubera Jun 26, 2025
783ffee
feat: implement responsive actions component in module wrapper
DilhanRubera Jun 26, 2025
2dff9d4
feat: change action buttons in contacts form to work with responsive …
DilhanRubera Jun 26, 2025
ab2d30b
feat: implement export popup feature and helper methods
DilhanRubera Jul 2, 2025
dd802da
refactor: change data table and data list to integrate exports popup
DilhanRubera Jul 2, 2025
4a55c75
feat: integrate exports popup in contacts module
DilhanRubera Jul 2, 2025
a9524c8
Merge remote-tracking branch 'upstream/develop' into develop
DilhanRubera Aug 11, 2025
7230d13
Merge remote-tracking branch 'upstream/develop' into develop
DilhanRubera Aug 12, 2025
e7657b1
Merge remote-tracking branch 'upstream/develop' into develop
DilhanRubera Aug 25, 2025
22ebccd
feat: add dynamic module route
DilhanRubera Aug 30, 2025
65cf430
feat: add dynamic module menu items
DilhanRubera Aug 30, 2025
c64c599
feat: update app layout to accomadate dynamic modules
DilhanRubera Aug 30, 2025
2d03094
feat: add breadcrumbs for dynamic modules
DilhanRubera Aug 30, 2025
955f4ed
refactor: change modulepath to allow strings for dynamic modules
DilhanRubera Aug 30, 2025
385edff
feat: add method for dynamic module navigation
DilhanRubera Aug 30, 2025
f269bc9
feat: update generic form to allow dynamic module navigation
DilhanRubera Aug 30, 2025
960f08d
feat: update data management and spreadsheet import to accomadate dyn…
DilhanRubera Aug 30, 2025
9164f97
feat: add dynamic module loader to load dynamic modules from config
DilhanRubera Aug 30, 2025
1d09f2d
fix: allow data time fields to be null to allow for editing
DilhanRubera Aug 30, 2025
ff2ca8e
Merge remote-tracking branch 'upstream/develop' into feature/dynamic-…
DilhanRubera Aug 31, 2025
35b9db3
refactor: update swagger files
DilhanRubera Aug 31, 2025
a076f5c
Merge remote-tracking branch 'upstream/develop' into feature/dynamic-…
DilhanRubera Sep 11, 2025
ee2db28
Merge remote-tracking branch 'upstream/develop' into feature/dynamic-…
DilhanRubera Sep 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { TranslationDraftProvider } from "@providers/translation-draft-provider"
import { LayoutProvider, useLayout } from "@providers/layout-provider";
import "react-toastify/dist/ReactToastify.css";
import { Auth } from "./features/auth/auth";
import { DynamicGenericModuleRoutes } from "@features/dynamic-module-loader";

export const App = () => {
// Define menu categories for breadcrumbs
Expand Down Expand Up @@ -56,7 +57,20 @@ export const App = () => {
const firstPath = paths[0];
const breadcrumbs: Breadcrumb[] = [];
let currentBreadcrumb = "";
if (firstPath && menuCategories[firstPath]) {

if (paths[0] === "modules" && paths[1]) {
const moduleName = paths[1];
const displayName = moduleName
.split("-")
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
.join(" ");
breadcrumbs.push({
linkText: "DYNAMIC",
toRoute: `/modules/${moduleName}`,
isCategory: true,
});
currentBreadcrumb = displayName;
} else if (firstPath && menuCategories[firstPath]) {
breadcrumbs.push({
linkText: menuCategories[firstPath].category,
toRoute: `/${firstPath}`,
Expand Down Expand Up @@ -124,7 +138,11 @@ export const App = () => {
path={`${coreModuleRoute.template}/*`}
element={<ModuleLoader />}
/>
</Route>
<Route
path="/modules/:moduleName/*"
element={<DynamicGenericModuleRoutes />}
/>
</Route>
</Routes>
</BrowserRouter>
</ErrorDetailsModalProvider>
Expand Down
16 changes: 11 additions & 5 deletions src/components/app-layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ interface AppLayoutProps {
fullWidth?: boolean;
}

type MenuItem = {
export type MenuItem = {
id: string;
label: string;
icon: React.ReactNode;
onClick: () => void;
icon: React.ReactNode | string;
entity: string;
route: string;
onClick: (navigate: (to: string) => void) => void;
isSelected: boolean;
};

interface SidebarMenuSection {
export interface SidebarMenuSection {
header: string;
items: MenuItem[];
}
Expand All @@ -43,7 +45,11 @@ export const AppLayout = ({
const { moduleName } = useRouteParams(coreModuleRoute);
const { config, loading: configLoading } = useConfig();

const menuItems = buildMenuItems(config?.entities, moduleName) as SidebarMenuSection[];
const menuItems = buildMenuItems(
config?.entities,
moduleName,
config?.modules ?? undefined
) as SidebarMenuSection[];
const menuLoading = configLoading;

// Pass drawer state to Sidebar and update container class
Expand Down
24 changes: 18 additions & 6 deletions src/components/data-management/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import {
} from "@mui/material";
import { DeleteButtonContainer } from "./index.styled";
import { Trash2, Edit } from "lucide-react";
import { useCoreModuleNavigation, useNotificationsService } from "@hooks";
import {
useCoreModuleNavigation,
useDynamicModuleNavigation,
useNotificationsService,
} from "@hooks";
import { HttpResponse, ProblemDetails } from "@lib/network/swagger-client";
import { useErrorDetailsModal } from "@providers/error-details-modal-provider";
import { execDeleteWithToast } from "utils/general-helper";
Expand Down Expand Up @@ -100,6 +104,7 @@ export const DataManagementBlock = ({
const { notificationsService } = useNotificationsService();
const { Show: showErrorModal } = useErrorDetailsModal();
const handleNavigation = useCoreModuleNavigation();
const handleDynamicModuleNavigation = useDynamicModuleNavigation();
const navigate = useNavigate();
const { moduleName } = useRouteParams(coreModuleRoute);

Expand All @@ -122,19 +127,26 @@ export const DataManagementBlock = ({
const deleteRecord = async () => {
try {
setIsDeleting(true);
await handleDeleteAsync(itemId);
if (onDeleted) {
onDeleted();
await handleDeleteAsync(itemId!);
const pathSegments = window.location.pathname.split("/");
if (pathSegments[1] === "modules") {
handleDynamicModuleNavigation(successNavigationRoute);
} else {
handleNavigation(successNavigationRoute);
}
handleNavigation(successNavigationRoute);
} catch (error) {
setIsDeleting(false);
throw error;
}
};

const editRecord = async () => {
navigate(`/${moduleName}/${itemId}/edit`);
const pathSegments = window.location.pathname.split("/");
if (pathSegments[1] === "modules") {
navigate(`/modules/${moduleName}/${itemId}/edit`);
} else {
navigate(`/${moduleName}/${itemId}/edit`);
}
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/generic-components/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface BasicTypeForGeneric {

export const getBreadcrumbLinks = (
moduleName: string,
modulePath: CoreModule
modulePath: CoreModule | string
): BreadcrumbLink[] => {
return [
...dataListBreadcrumbLinks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const DatetimeEdit = ({
size={"small"}
fullWidth
variant="outlined"
value={dayjs(value)}
value={value ? dayjs(value) : null}
onChange={(newValue) => {
onChangeValue && onChangeValue(newValue ? newValue.toDate() : null);
}}
Expand Down
27 changes: 23 additions & 4 deletions src/components/generic-components/generic-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import { validate } from "@components/generic-components/edit-components/validator";
import { ArrayEdit } from "./edit-components/array-edit";
import { StyledDivider } from "./index.styled";
import { useCoreModuleNavigation } from "@hooks";
import { useCoreModuleNavigation, useDynamicModuleNavigation } from "@hooks";
import { TextView } from "./view-components/text-view";
import { BoolView } from "./view-components/bool-view";
import { DateTimeView } from "./view-components/datetime-view";
Expand Down Expand Up @@ -112,6 +112,7 @@ export function GenericForm<TView extends BasicTypeForGeneric, TCreate, TUpdate>
}: GenericFormProps<TView, TCreate, TUpdate>) {
const { setBusy, setSaving } = useModuleWrapperContext();
const handleCoreNavigation = useCoreModuleNavigation();
const handleDynamicModuleNavigation = useDynamicModuleNavigation();
const [validationResult, setValidationResult] = useState<ValidationResult>();
const itemId = getItemId();

Expand Down Expand Up @@ -195,6 +196,13 @@ export function GenericForm<TView extends BasicTypeForGeneric, TCreate, TUpdate>
case "number":
initValues[field.name] = 0;
break;
case "string":
if (field.format === "date-time") {
initValues[field.name] = null;
} else {
initValues[field.name] = "";
}
break;
default:
initValues[field.name] = "";
break;
Expand Down Expand Up @@ -258,11 +266,22 @@ export function GenericForm<TView extends BasicTypeForGeneric, TCreate, TUpdate>
};

const cancel = () => {
const currentPath = window.location.pathname;
const modulePath = currentPath.split("/")[1];
handleCoreNavigation(modulePath);
navigateToListView();
};

function navigateToListView() {
const currentPath = window.location.pathname;
const pathSegments = currentPath.split("/");
let modulePath;
if (pathSegments[1] === "modules") {
modulePath = pathSegments[2];
handleDynamicModuleNavigation(modulePath);
} else {
modulePath = pathSegments[1];
handleCoreNavigation(modulePath);
}
}

const isValidUpdate = (field: DtoField) => {
if (field.type == "boolean" && (values[field.name] === true || values[field.name] === false))
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/components/generic-components/generic-module.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ interface ExtraActions {
showFiltersPanel?: boolean;
}

interface GenericModuleProps<TView extends BasicTypeForGeneric, TCreate, TUpdate> {
export interface GenericModuleProps<TView extends BasicTypeForGeneric, TCreate, TUpdate> {
moduleName: string;
modulePath: CoreModule;
modulePath: CoreModule | string;
addButtonContent?: string | ReactNode | undefined;
extraActions?: ExtraActions | undefined;
tableProps?: GenericDataGridProps<TView>;
Expand Down
13 changes: 12 additions & 1 deletion src/components/icon-map/icon-fuzzy-search.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { iconKeywordMap, defaultIcon } from "./icon-map";
import { iconKeywordMap, defaultIcon, defaultIconKey } from "./icon-map";

export function getSectionIcon(title: string) {
if (!title) return defaultIcon;
Expand All @@ -11,3 +11,14 @@ export function getSectionIcon(title: string) {
}
return defaultIcon;
}

export function getSectionIconKey(title: string): string {
if (!title) return defaultIconKey;
const lowerTitle = title.toLowerCase();
for (const { keywords, key } of iconKeywordMap) {
if (keywords.some((kw) => lowerTitle.includes(kw))) {
return key;
}
}
return defaultIconKey;
}
13 changes: 12 additions & 1 deletion src/components/icon-map/icon-map.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { User, HelpCircle, MessageCircle, Info, Code2 } from "lucide-react";
import { User, HelpCircle, MessageCircle, Info, Code2, School } from "lucide-react";

export const iconKeywordMap = [
{
keywords: ["author details", "author", "user", "creator", "writer"],
icon: User,
key: "user",
},
{
keywords: ["comment body", "comment", "body", "text", "message"],
icon: MessageCircle,
key: "message",
},
{
keywords: ["context", "background", "about", "reference"],
icon: Info,
key: "info",
},
{
keywords: ["meta", "metadata", "details", "info"],
icon: Code2,
key: "code2",
},
{
keywords: ["student", "school"],
icon: School,
key: "student",
},
];
export const defaultIcon = HelpCircle;

export const defaultIconKey = "help";
19 changes: 17 additions & 2 deletions src/components/spreadsheet-import/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { Fragment, useState } from "react";
import { ReactSpreadsheetImport } from "react-spreadsheet-import";
import { Result } from "react-spreadsheet-import/types/types";
import { StyledBackdrop } from "./index.styled";
import { useCoreModuleNavigation, useNotificationsService } from "@hooks";
import {
useCoreModuleNavigation,
useDynamicModuleNavigation,
useNotificationsService,
} from "@hooks";
import { getImportFields } from "utils/import-file-helper";

interface csvImportPorps {
Expand All @@ -16,6 +20,7 @@ interface csvImportPorps {

export const CsvImport = ({ isOpen, onClose, onUpload, object, endRoute }: csvImportPorps) => {
const handleNavigation = useCoreModuleNavigation();
const handleDynamicModuleNavigation = useDynamicModuleNavigation();
const { notificationsService } = useNotificationsService();
const [isUploading, setIsUploading] = useState(false);

Expand All @@ -37,9 +42,19 @@ export const CsvImport = ({ isOpen, onClose, onUpload, object, endRoute }: csvIm

const handleSuccess = () => {
notificationsService.success("Data import completed.");
handleNavigation(endRoute);
navigateToView();
};

function navigateToView() {
const currentPath = window.location.pathname;
const pathSegments = currentPath.split("/");
if (pathSegments[1] === "modules") {
handleDynamicModuleNavigation(endRoute);
} else {
handleNavigation(endRoute);
}
}

return (
<Fragment key={"spreadsheet-import"}>
<ReactSpreadsheetImport
Expand Down
Loading