Skip to main content

Account Management

Comprehensive account and settings management system for configuring organization details, managing users, setting up SSO authentication, configuring alert emails, scheduling reports, and manually entering flowmeter readings.


Overview

The Account Management module provides three main sections:

  1. Account Info - View and manage categories, units, and thresholds
  2. Account Settings - Configure organization details, users, alerts, reports, and SSO (password-protected)
  3. Manual Node Entry - Manually enter flowmeter readings for offline or virtual devices

Location: libs/manageAccount/

Routes:

  • /manage_account - Landing page
  • /manage_account/account_info - Account information
  • /manage_account/account_settings - Account settings (password-protected)
  • /manage_account/manual_node_entry - Manual flowmeter entry

Permissions:

  • ACCOUNT_SETTINGS - Required for account settings access
  • MANUAL_NODE_ENTRY - Required for manual flowmeter entry

Key Features

1. Account Landing Page

Central Hub with Three Cards:

Account Info Card

  • Icon: ErrorOutlineOutlined
  • Description: "Contains information such as Categories, Units and their respective thresholds"
  • Action: Navigate to Account Info page
  • Accessible: All users

Account Settings Card

  • Icon: Settings
  • Badge: "SSO Registration Here"
  • Description: "Password required to view and edit settings"
  • Password Verification: Requires current password to access
  • Action: Verify password → Navigate to Account Settings
  • Accessible: Users with ACCOUNT_SETTINGS permission, OTP login users excluded

Manual Node Entry Card (Optional)

  • Visible: Only with MANUAL_NODE_ENTRY permission
  • Description: "Manually enter flowmeter readings"
  • Action: Navigate to Manual Entry page

Additional Info:

  • Displays company logo
  • Shows joining date: "Joined Aquagen: DD/MM/YYYY"
  • Next payment due date (hidden by default)

2. Account Info Page

View and manage account configuration data organized by service categories.

Features

Navigation Panel (Left Sidebar):

  • Service category tabs (Consumption, Quality, Stock, etc.)
  • Auto-scroll highlighting based on scroll position
  • Point count badges showing number of units per category
  • Back button to return to landing page

Main Content Area:

  • Category-wise unit listings with expandable sections
  • Unit details:
    • Unit name
    • Unit ID
    • Associated thresholds (daily, hourly, quality parameters)
    • Last updated timestamp
  • Editable threshold values (if enabled)
  • Save/Cancel buttons for changes

Password-Protected Save:

  • Click Save → Enter password dialog
  • Password verification before applying changes
  • Success notification after save
  • Auto-refresh data after update

Unsaved Changes Warning:

  • Browser prompt when navigating away with unsaved changes
  • Confirmation dialog before exit

Data Structure

AccountInfoPage: {
SERVICE_CATEGORY_1: {
name: "Consumption",
data: [
{
column1: "Category Name",
column2: [
{
unitName: "Borewell 1",
unitId: "UNIT_123",
threshold: 1000,
hourlyThreshold: 50,
lastUpdated: "25/02/2026 10:30 AM"
}
]
}
]
}
}

3. Account Settings Page

Comprehensive settings management with 5 sections (password-protected).

Password Verification

  • Enter current password on landing page
  • Validates credentials before allowing access
  • OTP users cannot access account settings
  • Session-based verification (resets on page reload)

Section 1: Account Details

Organization Information:

  • Industry Name: Organization display name
  • Industry Id: Unique identifier
  • Address: Full address with street, city, state, ZIP
  • Contact Person: Primary contact name
  • Email: Organization email
  • Phone: Contact number
  • Website: Organization website URL
  • Logo Upload: Company logo (image file upload)

Editable Fields:

  • All text fields editable inline
  • Image upload with preview
  • Real-time validation for email and phone
  • Character limits enforced

Section 2: Users Management

User List Table:

  • User name, email, role
  • Active/Inactive status
  • Last login timestamp
  • Edit/Delete actions

Add New User:

  • Name, email, password
  • Role selection (Admin, Manager, Operator, Viewer)
  • Permission assignment (33+ individual permissions)
  • Email verification on creation

Edit User:

  • Update user details
  • Change role and permissions
  • Reset password
  • Activate/Deactivate account

Delete User:

  • Confirmation dialog
  • Cannot delete yourself
  • Cannot delete last admin

Section 3: Alert Email Configuration

Alert Email Recipients:

  • Add multiple email addresses for alert notifications
  • Configure alert types per email:
    • Consumption alerts
    • Leakage detection
    • Offline device alerts
    • Quality threshold violations
    • Energy alerts
  • Email validation
  • Remove email recipients

Alert Frequency:

  • Instant alerts
  • Daily digest
  • Weekly summary

Section 4: Reports Configuration

Scheduled Reports:

  • Report Types:

    • Consumption report
    • Quality report
    • Stock report
    • Alert summary report
    • Water balance report
  • Schedule Configuration:

    • Daily (specific time)
    • Weekly (day and time)
    • Monthly (date and time)
  • Email Recipients: Multiple email addresses

  • Format: PDF or Excel

  • Sections: Select report sections to include

Report Preview:

  • Preview report before scheduling
  • Test email delivery

Section 5: SSO Login Configuration

Single Sign-On Setup:

Supported SSO Providers:

  • Microsoft Azure AD (MSAL)
  • Google Workspace (OAuth)

Azure AD Configuration:

  • Tenant ID
  • Client ID
  • Client Secret
  • Redirect URI
  • Domain whitelist for allowed email domains

Google OAuth Configuration:

  • Client ID
  • Client Secret
  • Authorized domains
  • Redirect URI

SSO User Management:

  • Add SSO email addresses
  • Domain-based auto-provisioning
  • Map SSO users to AquaGen roles
  • Remove SSO users
  • Test SSO login

SSO Changes Detection:

  • Tracks SSO configuration changes separately
  • Warns before navigating away with unsaved SSO changes
  • Validates email domains against configured domains

4. Manual Node Entry Page

Manually enter flowmeter readings for offline or virtual devices.

Use Cases

  • Offline flowmeters without connectivity
  • Virtual nodes without physical sensors
  • Backup data entry when sensors fail
  • Manual meter readings from field

Features

Device List:

  • Shows all manual entry-enabled flowmeters
  • Device name, last value, last updated time
  • Device type (RS485 or Pulse meter)

Data Entry Fields:

  • Date Picker: Select reading date (cannot be before device creation date)
  • Time Picker: Select reading time (30-minute intervals, rounded)
  • Value Input: Enter meter reading with validation
  • Min Time Validation: Cannot enter time before device creation time on same date

Validation Rules:

RS485 Meters:

  • Value cannot be less than previous value (cumulative reading)
  • Error message: "Value cannot be less than the previous value"

Pulse Meters:

  • Value cannot be negative (incremental pulses)
  • Error message: "You cannot enter negative values"

Save Behavior:

  • Save button enabled only when valid values entered
  • Confirm dialog before submitting
  • Success/error message after save
  • Auto-refresh device list after successful save

Unsaved Changes Protection:

  • Browser warning before page close
  • Dialog when clicking Back with unsaved entries
  • Option to save or discard changes

Device Display:

Unit Name: Borewell 1
Last Updated: 1250 Kilo Liters on 24/02/2026 03:30 PM

[Date Picker] [Time Picker] [Value Input]

Architecture

Data Flow

Key Components

1. AccountStoreContextProvider

  • Purpose: Global state management for account data
  • Location: libs/manageAccount/src/store/AccountStore.js
  • State Variables:
    • accountScreenData - All account data
    • lastUpdatedTime - Last data refresh time
    • updatedOperations - Pending changes array
    • isVerifiedForAccountSetting - Password verification status
    • isVerifiedForManualNodeEntry - Manual entry verification
    • isLoading - Loading state

Context Value:

{
accountScreenData: {
joiningDate: "01/01/2024",
AccountInfoPage: {...},
AccountSettingPage: {
industryName: "ABC Corp",
email: "info@abc.com",
users: [...],
alertEmails: [...],
reports: [...],
sso: [...]
}
},
isLoading: false,
isVerifiedForAccountSetting: false,
fetchAccountData: () => {},
updateAccountInfo: () => {},
fetchLastUpdatedTime: (path) => {},
clearLastUpdatedTime: () => {}
}

2. AccountLandingPage

  • Purpose: Main entry point with three action cards
  • Location: libs/manageAccount/src/subPages/AccountLandingPage.jsx
  • Features:
    • Account Info card (all users)
    • Account Settings card (password-protected)
    • Manual Node Entry card (permission-based)
    • Company logo display
    • Joining date display

3. AccountInfoPage

  • Purpose: View/edit categories and units
  • Location: libs/manageAccount/src/subPages/AccountInfoPage.jsx
  • Features:
    • Left navigation panel
    • Category sections
    • Unit tables with thresholds
    • Password-protected save
    • Unsaved changes warning

4. AccountSettingPage

  • Purpose: Organization and system settings
  • Location: libs/manageAccount/src/subPages/AccountSettingPage.jsx
  • Features:
    • 5 section tabs (Account, Users, Alerts, Reports, SSO)
    • Scroll-based active section highlighting
    • Save/Cancel buttons
    • Changes detection
    • Navigation blocker for unsaved changes
    • Responsive mobile view with tabs

5. ManualNodePage

  • Purpose: Manual flowmeter data entry
  • Location: libs/manageAccount/src/subPages/ManualNodePage.jsx
  • Features:
    • Device list with last readings
    • Date/time pickers
    • Value input with validation
    • Save/cancel with confirmation
    • Unsaved changes warning

6. ManualNodeStore

  • Purpose: State management for manual node entry
  • Location: libs/manageAccount/src/store/ManualNodeStore.js
  • State Variables:
    • manualNodeData - List of manual entry devices
    • newValues - Pending entries object
    • showMessage - Error/success messages
    • saveButtonDisable - Validation state
    • fullScreenLoader - Loading state

API Integration

Get Account Data

GET /accounts/details

Response: {
joiningDate: "01/01/2024",
AccountInfoPage: {
SERVICE_CATEGORY_1: {
name: "Consumption",
data: [...]
}
},
AccountSettingPage: {
industryName: "ABC Corp",
industryId: "IND_123",
address: "123 Main St, City, State 12345",
email: "info@abc.com",
phone: "+1234567890",
website: "www.abc.com",
logo: "https://...",
users: [...],
alertEmails: [...],
reports: [...],
sso: [...]
}
}

Update Account Info

PATCH /accounts/info
Request Body: {
operations: [
{
op: "replace",
path: "/units/UNIT_123/threshold",
value: 1200
},
{
op: "replace",
path: "/units/UNIT_123/hourlyThreshold",
value: 60
}
]
}

Response: {
status: 200,
message: "Account info updated successfully"
}

Update Account Settings

POST /accounts/settings
Request Body: {
industryName: "ABC Corp",
address: "123 Main St",
email: "info@abc.com",
phone: "+1234567890",
website: "www.abc.com",
users: [...],
alertEmails: [...],
reports: [...],
sso: [...]
}

Response: {
status: 200,
message: "Settings updated successfully"
}
POST /accounts/settings/logo
Content-Type: multipart/form-data

Request: FormData with 'image' field

Response: {
status: 200,
logoUrl: "https://storage.com/logos/abc-corp.png"
}

Get Manual Node Data

GET /virtualNodes/data

Response: {
data: [
{
unitId: "UNIT_123",
unitName: "Borewell 1",
value: 1250.5,
flowFactor: 1000, // 1 = Liters, 1000 = Kilo Liters
meterType: "RS485", // or "PULSE"
createdOn: "24/02/2026 03:30 PM"
}
]
}

Post Manual Node Data

POST /virtualNodes/data
Request Body: {
entries: [
{
unitId: "UNIT_123",
value: 1300.5,
date_time: "25/02/2026T10:30:00"
}
]
}

Response: {
status: 200,
message: "Manual entries saved successfully"
}

Usage Examples

1. Navigate to Account Settings with Password

import { useContext, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { AccountStoreContext } from '@aquagen-mf-webapp/manageAccount/store/AccountStore';
import { LoginController } from '@aquagen-mf-webapp/components/pages/login/loginController';

function AccountSettingsAccess() {
const accountStore = useContext(AccountStoreContext);
const navigate = useNavigate();
const [password, setPassword] = useState('');
const [error, setError] = useState(false);

const handleAccessSettings = async () => {
const username = appStore?.loginData?.username;

if (username && password) {
const response = await LoginController.defaultLogin(username, password);

if (response) {
accountStore.setIsVerifiedForAccountSetting(true);
navigate('./account_settings');
setError(false);
} else {
setError(true);
}
}
};

return (
<TextField
type="password"
value={password}
error={error}
helperText={error ? "Wrong password" : ""}
onChange={(e) => setPassword(e.target.value)}
/>
);
}

2. Update Account Info with Operations

const updateThreshold = (unitId, newThreshold) => {
const operations = [
{
op: "replace",
path: `/units/${unitId}/threshold`,
value: newThreshold
}
];

await AccountController.updateAccountInfo({ operations });
await accountStore.fetchAccountData(); // Refresh
};

3. Add SSO Email

const addSSOEmail = () => {
const newSSOUser = {
email: "user@company.com",
domain: "company.com",
provider: "azure", // or "google"
isNew: true,
isEdited: false,
isDeleted: false
};

setFormData(prev => ({
...prev,
sso: [...prev.sso, newSSOUser]
}));

setChangesHappened(true);
};

4. Manual Node Entry with Validation

import { ManualNodeHelper } from '@aquagen-mf-webapp/manageAccount/helper/manualNodeHelperInstance';

const handleManualEntry = (nodeData, enteredValue) => {
// Validate RS485 meter (cumulative)
if (
enteredValue < nodeData.value &&
nodeData.meterType === ManualNodeHelper.i.deviceTypeEnum.RS485.id
) {
setError('Value cannot be less than the previous value');
return;
}

// Validate Pulse meter (incremental)
if (
enteredValue < 0 &&
nodeData.meterType === ManualNodeHelper.i.deviceTypeEnum.PULSE.id
) {
setError('You cannot enter negative values');
return;
}

// Valid entry
const entry = {
unitId: nodeData.unitId,
value: Number(enteredValue),
date_time: `${date.format('DD/MM/YYYY')}T${time.format('HH:mm')}:00`
};

manualNodeStore.setNewValues(prev => ({
...prev,
[entry.unitId]: entry
}));
};

5. Block Navigation with Unsaved Changes

import { useBlocker } from 'react-router-dom';

const blocker = useBlocker(({ currentLocation, nextLocation }) => {
if (currentLocation.pathname !== nextLocation.pathname) {
if (changesHappened || ssoChangesHappened) {
setIsBlocked(true);
return true; // Block navigation
}
}

setIsBlocked(false);
return false; // Allow navigation
});

// Show exit confirmation dialog
<AccountSettingsExitCard
open={isBlocked}
onExit={() => {
blocker.proceed(); // Allow blocked navigation
}}
onStay={() => {
blocker.reset(); // Cancel blocked navigation
}}
/>

Manual Node Helper Configuration

ManualNodeHelper.i.deviceTypeEnum = {
RS485: {
id: 'RS485',
displayName: 'RS485 Meter',
valueType: 'Cumulative Reading',
validation: 'Cannot decrease'
},
PULSE: {
id: 'PULSE',
displayName: 'Pulse Meter',
valueType: 'Pulse Count',
validation: 'Cannot be negative'
}
};

// Round time to nearest 30 minutes
ManualNodeHelper.i.roundToNearest30Minutes = (momentTime) => {
const minutes = momentTime.minutes();
const roundedMinutes = minutes < 30 ? 0 : 30;
return momentTime.clone().minutes(roundedMinutes).seconds(0);
};

// Get minimum allowed time based on device creation
ManualNodeHelper.i.getMinTime = (createdOn, selectedDate) => {
if (selectedDate.isSame(createdOn, 'day')) {
return createdOn; // Same day: cannot enter before creation time
}
return moment().startOf('day'); // Different day: any time allowed
};

// Get value type with unit
ManualNodeHelper.i.getValueTypeWithUnit = (meterType, flowFactor) => {
const unit = flowFactor === 1000 ? 'Kilo Liters' : 'Liters';
return `Value (${unit})`;
};

SSO Helper Configuration

// Initialize SSO users with tracking fields
SSOHelper.initializeSSOUsers = (ssoUsers) => {
return ssoUsers.map(user => ({
...user,
isNew: false,
isEdited: false,
isDeleted: false
}));
};

// Check if SSO changes happened
SSOHelper.checkSSOChanges = (formData, settingData) => {
const currentSSO = formData.sso || [];
const originalSSO = settingData?.sso || [];

// Check for new users
if (currentSSO.some(user => user.isNew)) return true;

// Check for edited users
if (currentSSO.some(user => user.isEdited)) return true;

// Check for deleted users
if (currentSSO.some(user => user.isDeleted)) return true;

// Check for count mismatch
if (currentSSO.length !== originalSSO.length) return true;

return false;
};

Best Practices

1. Always Verify Password for Settings

useEffect(() => {
if (!accountStore.isVerifiedForAccountSetting) {
navigate(`../../${NavigationHelper.i.routes.MANAGE_ACCOUNT}`);
return;
}

return () => {
accountStore.setIsVerifiedForAccountSetting(false); // Reset on unmount
};
}, []);

2. Track Changes for Exit Warning

const [changesHappened, setChangesHappened] = useState(false);

// Mark changes on any field edit
const handleFieldChange = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }));
setChangesHappened(true);
};

// Reset after successful save
const handleSave = async () => {
await saveChanges();
setChangesHappened(false);
};

3. Validate Email Inputs

const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};

const handleEmailAdd = (email) => {
if (!validateEmail(email)) {
setError('Invalid email format');
return;
}

addEmail(email);
};

4. Handle Image Uploads Properly

const handleLogoUpload = async (file) => {
if (!file) return;

// Validate file type
if (!file.type.startsWith('image/')) {
setError('Please upload an image file');
return;
}

// Validate file size (e.g., max 5MB)
if (file.size > 5 * 1024 * 1024) {
setError('Image size must be less than 5MB');
return;
}

const formData = new FormData();
formData.append('image', file);

const response = await AccountDataSource.accountSettingsLogoUpdate(formData);

if (response) {
setFormData(prev => ({ ...prev, logo: response.logoUrl }));
}
};

5. Debounce Password Verification

import { debounce } from 'lodash';

const passVerifyandNavigate = debounce(async (password) => {
if (password.includes(' ')) {
setPasswordError(true);
setErrorMessage("Password shouldn't contain spaces");
return;
}

const response = await LoginController.defaultLogin(username, password);
// Handle response...
}, 500); // Wait 500ms after last keystroke

Troubleshooting

Cannot Access Account Settings

Cause: Not verified or OTP login Solution: Check verification status and login type

if (loginType === 'OTP') {
// OTP users cannot access settings
return <Typography>Account settings not available for OTP login</Typography>;
}

if (!accountStore.isVerifiedForAccountSetting) {
navigate('/manage_account');
}

Manual Node Save Disabled

Cause: Validation errors or no changes Solution: Check validation and newValues

const isSaveDisabled =
!_.keys(manualNodeStore.newValues).length || // No entries
manualNodeStore.isLoading || // Currently loading
manualNodeStore.saveButtonDisable; // Validation errors

// Check for validation errors
Object.values(manualNodeStore.newValues).forEach(entry => {
if (hasValidationError(entry)) {
manualNodeStore.setSaveButtonDisable(true);
}
});

SSO Changes Not Detected

Cause: Missing change tracking flags Solution: Ensure isNew/isEdited/isDeleted flags are set

// When adding SSO user
const newUser = {
email: "user@company.com",
isNew: true, // Mark as new
isEdited: false,
isDeleted: false
};

// When editing SSO user
const editUser = (userId) => {
setFormData(prev => ({
...prev,
sso: prev.sso.map(user =>
user.id === userId
? { ...user, isEdited: true } // Mark as edited
: user
)
}));
};

Responsive Design

Desktop (md+)

  • Sidebar navigation visible
  • Two-column layout (navigation + content)
  • Sticky sidebar for easy section access
  • Full-width forms

Mobile (xs-sm)

  • Tabs at top instead of sidebar
  • Single-column layout
  • Collapsible sections
  • Full-width inputs
  • Touch-friendly buttons

Responsive Breakpoint:

const isMobile = useMediaQuery(theme.breakpoints.down('sm'));

Analytics Tracking

// Page view
AnalyticsService.sendEvent(AnalyticEvents.PAGE_VIEW, {}, true);

// Account info access
AnalyticsService.sendEvent(AnalyticEvents.ACCOUNT_INFO_CLICK);

// Account settings access
AnalyticsService.sendEvent(AnalyticEvents.ACCOUNT_SETTINGS_CLICK);

// Manual node entry save
AnalyticsService.sendEvent(
AnalyticEvents.MANUAL_NODE_VALUE_CHANGE_SAVE_CLICK,
unitIds
);


Last Updated: February 2026 Module Location: libs/manageAccount/