Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
6 changes: 3 additions & 3 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
REACT_APP_API_URL=http://localhost:4000
NODE_ENV=development
MONGO_URL=mongodb://localhost:27017/erxes
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
MONGO_URL=mongodb+srv://enkhtuvshinej:mXSfJ0OgPvw3cGr2@erxes-local.xe5ccpj.mongodb.net/erxes_local?retryWrites=true&w=majority&appName=erxes-local
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Duplicate MONGO_URL variables will cause configuration issues. Only the last one (line 3) will be used. Remove one of these.

Suggested change
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
MONGO_URL=mongodb+srv://enkhtuvshinej:mXSfJ0OgPvw3cGr2@erxes-local.xe5ccpj.mongodb.net/erxes_local?retryWrites=true&w=majority&appName=erxes-local
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
Prompt To Fix With AI
This is a comment left during a code review.
Path: .env.sample
Line: 2:3

Comment:
**logic:** Duplicate `MONGO_URL` variables will cause configuration issues. Only the last one (line 3) will be used. Remove one of these.

```suggestion
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Production MongoDB credentials with username enkhtuvshinej and password are exposed in the sample file. This is a critical security vulnerability - remove these credentials immediately.

Suggested change
MONGO_URL=mongodb+srv://enkhtuvshinej:mXSfJ0OgPvw3cGr2@erxes-local.xe5ccpj.mongodb.net/erxes_local?retryWrites=true&w=majority&appName=erxes-local
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
Prompt To Fix With AI
This is a comment left during a code review.
Path: .env.sample
Line: 3:3

Comment:
**logic:** Production MongoDB credentials with username `enkhtuvshinej` and password are exposed in the sample file. This is a critical security vulnerability - remove these credentials immediately.

```suggestion
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple MONGO_URL definitions and embedded credentials detected. Use only one MONGO_URL and avoid hardcoding sensitive credentials in sample files.

Suggested change
MONGO_URL=mongodb+srv://enkhtuvshinej:mXSfJ0OgPvw3cGr2@erxes-local.xe5ccpj.mongodb.net/erxes_local?retryWrites=true&w=majority&appName=erxes-local

NODE_OPTIONS=--max-old-space-size=1536
ENABLED_PLUGINS=frontline
ENABLED_PLUGINS=tourism,frontline
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const POS_CURSOR_SESSION_KEY = 'pos-cursor';
export const LEADS_CURSOR_SESSION_KEY = 'leads-cursor';
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useLocation } from 'react-router';
import { PosPath } from '~/modules/types/path/PosPath';
import { LEADS_CURSOR_SESSION_KEY, POS_CURSOR_SESSION_KEY } from '~/modules/constants/PosCursorSessionKey';


export const useIsPosLeadSessionKey = () => {
const { pathname } = useLocation();

const isLead = pathname.includes(PosPath.Leads);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Using pathname.includes() could match unintended routes - consider using exact path matching or startsWith() for more precise routing logic

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/plugins/pos_ui/src/modules/pos-detail/hooks/UsePosLeadSessionKey.tsx
Line: 9:9

Comment:
**logic:** Using `pathname.includes()` could match unintended routes - consider using exact path matching or startsWith() for more precise routing logic

How can I resolve this? If you propose a fix, please make it concise.

return {
isLead,
sessionKey: isLead
? LEADS_CURSOR_SESSION_KEY
: POS_CURSOR_SESSION_KEY,
};
};
168 changes: 168 additions & 0 deletions frontend/plugins/pos_ui/src/modules/pos/PosFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {
IconCalendar,
IconCalendarPlus,
IconCalendarTime,
IconCalendarUp,
IconLabel,
IconSearch,
} from '@tabler/icons-react';
import {
Combobox,
Command,
Filter,
useFilterQueryState,
useMultiQueryState,
} from 'erxes-ui';
import { SelectMember, TagsFilter, SelectBrand } from 'ui-modules';
import { PosTotalCount } from './PosTotalCount';
import { PosHotKeyScope } from '../types/posHotkeyScope';
import { useIsPosLeadSessionKey } from '../pos-detail/hooks/UsePosLeadSessionKey';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Use absolute import paths instead of relative paths per coding standards

Context Used: Rule from dashboard - Use absolute import paths instead of relative paths when importing modules in TypeScript/JavaScript ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/plugins/pos_ui/src/modules/pos/PosFilter.tsx
Line: 16:19

Comment:
**style:** Use absolute import paths instead of relative paths per coding standards

**Context Used:** Rule from `dashboard` - Use absolute import paths instead of relative paths when importing modules in TypeScript/JavaScript ... ([source](https://app.greptile.com/review/custom-context?memory=c22f4dca-4fa7-48c2-911a-3f50a8f6d5a8))

How can I resolve this? If you propose a fix, please make it concise.

const PosFilterPopover = () => {
const [queries] = useMultiQueryState<{
tags: string[];
searchValue: string;
created: string;
updated: string;
lastSeen: string;
brand: string;
}>(['tags', 'searchValue', 'created', 'updated', 'lastSeen', 'brand']);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'birthday' filter UI is defined later but not included in the useMultiQueryState keys. Verify if this omission is intentional.


const hasFilters = Object.values(queries || {}).some(
(value) => value !== null,
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add 'birthday' to the query keys array.

The birthday filter is defined in the UI (lines 70-73, 89-91, 107-109) but is missing from the useMultiQueryState query keys array. This causes hasFilters to not detect when the birthday filter is active, resulting in the Filter.Trigger not showing as filtered despite the filter being applied.

Apply this diff to fix the issue:

   const [queries] = useMultiQueryState<{
     tags: string[];
     searchValue: string;
     created: string;
     updated: string;
     lastSeen: string;
     brand: string;
-  }>(['tags', 'searchValue', 'created', 'updated', 'lastSeen', 'brand']);
+    birthday: string;
+  }>(['tags', 'searchValue', 'created', 'updated', 'lastSeen', 'brand', 'birthday']);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const PosFilterPopover = () => {
const [queries] = useMultiQueryState<{
tags: string[];
searchValue: string;
created: string;
updated: string;
lastSeen: string;
brand: string;
}>(['tags', 'searchValue', 'created', 'updated', 'lastSeen', 'brand']);
const hasFilters = Object.values(queries || {}).some(
(value) => value !== null,
);
const PosFilterPopover = () => {
const [queries] = useMultiQueryState<{
tags: string[];
searchValue: string;
created: string;
updated: string;
lastSeen: string;
brand: string;
birthday: string;
}>(['tags', 'searchValue', 'created', 'updated', 'lastSeen', 'brand', 'birthday']);
const hasFilters = Object.values(queries || {}).some(
(value) => value !== null,
);
🤖 Prompt for AI Agents
In frontend/plugins/pos_ui/src/modules/pos/PosFilter.tsx around lines 20 to 32,
the 'birthday' query key is missing from the useMultiQueryState keys array so
hasFilters doesn't detect the birthday filter; add 'birthday' to the array of
keys passed to useMultiQueryState (i.e., include 'birthday' alongside 'tags',
'searchValue', 'created', 'updated', 'lastSeen', 'brand') so the birthday filter
state is tracked and hasFilters reflects it.


return (
<>
<Filter.Popover scope={PosHotKeyScope.PosPage}>
<Filter.Trigger isFiltered={hasFilters} />
<Combobox.Content>
<Filter.View>
<Command>
<Filter.CommandInput
placeholder="Filter"
variant="secondary"
className="bg-background"
/>
<Command.List className="p-1">
<Filter.Item value="searchValue" inDialog>
<IconSearch />
Search
</Filter.Item>
<TagsFilter />
<Filter.Item value="brand">
<IconLabel />
Brand
</Filter.Item>
<SelectMember.FilterItem />
<Command.Separator className="my-1" />
<Filter.Item value="created">
<IconCalendarPlus />
Created At
</Filter.Item>
<Filter.Item value="updated">
<IconCalendarUp />
Updated At
</Filter.Item>
<Filter.Item value="lastSeen">
<IconCalendarTime />
Last Seen At
</Filter.Item>
<Filter.Item value="birthday">
<IconCalendar />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

happy birthday

Birthday
</Filter.Item>
</Command.List>
</Command>
</Filter.View>
<SelectMember.FilterView />
<SelectBrand.FilterView />
<TagsFilter.View tagType="core:pos" />
<Filter.View filterKey="created">
<Filter.DateView filterKey="created" />
</Filter.View>
<Filter.View filterKey="updated">
<Filter.DateView filterKey="updated" />
</Filter.View>
<Filter.View filterKey="lastSeen">
<Filter.DateView filterKey="lastSeen" />
</Filter.View>
<Filter.View filterKey="birthday">
<Filter.DateView filterKey="birthday" />
</Filter.View>
</Combobox.Content>
</Filter.Popover>
<Filter.Dialog>
<Filter.View filterKey="searchValue" inDialog>
<Filter.DialogStringView filterKey="searchValue" />
</Filter.View>
<Filter.View filterKey="created" inDialog>
<Filter.DialogDateView filterKey="created" />
</Filter.View>
<Filter.View filterKey="updated" inDialog>
<Filter.DialogDateView filterKey="updated" />
</Filter.View>
<Filter.View filterKey="lastSeen" inDialog>
<Filter.DialogDateView filterKey="lastSeen" />
</Filter.View>
<Filter.View filterKey="birthday" inDialog>
<Filter.DialogDateView filterKey="birthday" />
</Filter.View>
</Filter.Dialog>
</>
);
};

export const PosFilter = () => {
const [searchValue] = useFilterQueryState<string>('searchValue');
const { sessionKey } = useIsPosLeadSessionKey();

return (
<Filter id="pos-filter" sessionKey={sessionKey}>
<Filter.Bar>
<Filter.BarItem queryKey="searchValue">
<Filter.BarName>
<IconSearch />
Search
</Filter.BarName>
<Filter.BarButton filterKey="searchValue" inDialog>
{searchValue}
</Filter.BarButton>
</Filter.BarItem>
<TagsFilter.Bar tagType="core:pos" />
<Filter.BarItem queryKey="created">
<Filter.BarName>
<IconCalendarPlus />
Created At
</Filter.BarName>
<Filter.Date filterKey="created" />
</Filter.BarItem>
<Filter.BarItem queryKey="updated">
<Filter.BarName>
<IconCalendarUp />
Updated At
</Filter.BarName>
<Filter.Date filterKey="updated" />
</Filter.BarItem>
<Filter.BarItem queryKey="lastSeen">
<Filter.BarName>
<IconCalendarTime />
Last Seen At
</Filter.BarName>
<Filter.Date filterKey="lastSeen" />
</Filter.BarItem>
<Filter.BarItem queryKey="birthday">
<Filter.BarName>
<IconCalendar />
Birthday
</Filter.BarName>
<Filter.Date filterKey="birthday" />
</Filter.BarItem>
<SelectMember.FilterBar />
<SelectBrand.FilterBar />
<PosFilterPopover />
<PosTotalCount />
</Filter.Bar>
</Filter>
);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

LGTM! Consider verifying SelectMember filter detection.

The component structure is well-organized and follows coding guidelines correctly. The use of sessionKey from useIsPosLeadSessionKey ensures proper filter state management between POS and Leads views.

One additional consideration: SelectMember.FilterBar (line 160) may have its own query key (e.g., assignedUserId) that might also be missing from PosFilterPopover's hasFilters check. If SelectMember's filter state doesn't trigger the filtered indicator on the Filter.Trigger, you'll need to add its query key to the array in PosFilterPopover as well.

Run the following script to check what query key SelectMember uses:


🏁 Script executed:

#!/bin/bash
# Description: Find the query key used by SelectMember.FilterBar

# Search for the query key definition in SelectMember components
ast-grep --pattern 'useFilterQueryState$$$' frontend/libs/ui-modules/src/modules/team-members/components/SelectMember.tsx

# Also search for any hardcoded query key strings
rg -n "queryKey.*=" frontend/libs/ui-modules/src/modules/team-members/components/SelectMember.tsx

Length of output: 60


Add 'assignedTo' to PosFilterPopover.hasFilters
PosFilterPopover currently doesn’t include the SelectMember default queryKey ('assignedTo') in its hasFilters array, so member selections won’t trigger the active-filter indicator. Update hasFilters in PosFilterPopover to include 'assignedTo'.

🤖 Prompt for AI Agents
In frontend/plugins/pos_ui/src/modules/pos/PosFilter.tsx around lines 115 to
167, PosFilterPopover's hasFilters array is missing the SelectMember default
queryKey 'assignedTo', so selecting a member doesn't mark the filter as active;
update the PosFilterPopover component to include 'assignedTo' in its hasFilters
array (add 'assignedTo' alongside the existing keys) so member selections
trigger the active-filter indicator.


17 changes: 17 additions & 0 deletions frontend/plugins/pos_ui/src/modules/pos/PosTotalCount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { isUndefinedOrNull, Skeleton } from 'erxes-ui';
import { useAtomValue } from 'jotai';
import { posTotalCountAtom } from '~/modules/states/PosCount';


export const PosTotalCount = () => {
const totalCount = useAtomValue(posTotalCountAtom);
return (
<div className="text-muted-foreground font-medium text-sm whitespace-nowrap h-7 leading-7">
{isUndefinedOrNull(totalCount) ? (
<Skeleton className="w-20 h-4 inline-block mt-1.5" />
) : (
`${totalCount} records found`
)}
</div>
);
};
3 changes: 3 additions & 0 deletions frontend/plugins/pos_ui/src/modules/states/PosCount.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ene ter chigeere ustaagui yu

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { atom } from 'jotai';

export const posTotalCountAtom = atom<number | null>(null);
9 changes: 9 additions & 0 deletions frontend/plugins/pos_ui/src/modules/types/path/PosPath.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export enum PosPath {
Index = '/contacts',
Customers = '/customers',
Leads = '/leads',
Companies = '/companies',
Vendors = '/vendors',
Clients = '/clients',
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Replace enum with const object map according to project guidelines. Enums are explicitly avoided in favor of maps.

Suggested change
export enum PosPath {
Index = '/contacts',
Customers = '/customers',
Leads = '/leads',
Companies = '/companies',
Vendors = '/vendors',
Clients = '/clients',
}
export const PosPath = {
Index: '/contacts',
Customers: '/customers',
Leads: '/leads',
Companies: '/companies',
Vendors: '/vendors',
Clients: '/clients',
} as const;
export type PosPath = typeof PosPath[keyof typeof PosPath];

Context Used: Context from dashboard - .cursorrules (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/plugins/pos_ui/src/modules/types/path/PosPath.tsx
Line: 1:8

Comment:
**style:** Replace enum with const object map according to project guidelines. Enums are explicitly avoided in favor of maps.

```suggestion
export const PosPath = {
  Index: '/contacts',
  Customers: '/customers',
  Leads: '/leads',
  Companies: '/companies',
  Vendors: '/vendors',
  Clients: '/clients',
} as const;

export type PosPath = typeof PosPath[keyof typeof PosPath];
```

**Context Used:** Context from `dashboard` - .cursorrules ([source](https://app.greptile.com/review/custom-context?memory=bf691a04-8aaa-40fe-8db5-b17d5fe3755f))

How can I resolve this? If you propose a fix, please make it concise.


9 changes: 7 additions & 2 deletions frontend/plugins/pos_ui/src/pages/PosIndexPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { IconCashRegister, IconPlus, IconSettings } from '@tabler/icons-react';
import { Breadcrumb, Button, Separator } from 'erxes-ui';
import { Breadcrumb, Button, PageSubHeader, Separator } from 'erxes-ui';
import { PageHeader } from 'ui-modules';
import { Link, useSearchParams } from 'react-router-dom';
import { PosRecordTable } from '@/components/PosRecordTable';
import { useAtom } from 'jotai';
import { PosCreate } from '@/create-pos/components/index/pos-create';
import { PosEdit } from '@/pos-detail/components/posDetail';
import { renderingPosCreateAtom } from '@/create-pos/states/renderingPosCreateAtom';
import { PosFilter } from '@/pos/PosFilter';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Extra trailing spaces after the import statement

Suggested change
import { PosFilter } from '@/pos/PosFilter';
import { PosFilter } from '@/pos/PosFilter';
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/plugins/pos_ui/src/pages/PosIndexPage.tsx
Line: 10:10

Comment:
**style:** Extra trailing spaces after the import statement

```suggestion
import { PosFilter } from '@/pos/PosFilter';
```

How can I resolve this? If you propose a fix, please make it concise.



export const PosIndexPage = () => {
const [, setSearchParams] = useSearchParams();
Expand All @@ -17,7 +19,7 @@ export const PosIndexPage = () => {
setSearchParams({ create: 'true' });
};
return (
<div className="flex flex-col h-full">
<div className="flex flex-col h-full">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Line contains excessive trailing whitespace that should be removed for cleaner code

Suggested change
<div className="flex flex-col h-full">
<div className="flex flex-col h-full">
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/plugins/pos_ui/src/pages/PosIndexPage.tsx
Line: 22:22

Comment:
**style:** Line contains excessive trailing whitespace that should be removed for cleaner code

```suggestion
    <div className="flex flex-col h-full">
```

How can I resolve this? If you propose a fix, please make it concise.

<PageHeader>
<PageHeader.Start>
<Breadcrumb>
Expand Down Expand Up @@ -48,6 +50,9 @@ export const PosIndexPage = () => {
</Button>
</PageHeader.End>
</PageHeader>
<PageSubHeader>
<PosFilter />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Missing proper indentation - should align with parent component structure

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/plugins/pos_ui/src/pages/PosIndexPage.tsx
Line: 54:54

Comment:
**style:** Missing proper indentation - should align with parent component structure

How can I resolve this? If you propose a fix, please make it concise.

</PageSubHeader>
<PosCreate />
<PosRecordTable />
<PosEdit />
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"dev:core-api": "npx nx run-many -t serve -p core-api gateway",
"dev:apis": "dotenv -e .env -- node scripts/start-api-dev.js",
"dev:uis": "dotenv -e .env -- node scripts/start-ui-dev.js",
"create-plugin": "node scripts/create-plugin.js"
"create-plugin": "node scripts/create-plugin.js",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,md}\"",
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,css,md}\""
},
"engines": {
"pnpm": ">=8",
Expand Down
Loading