Intercode SaaS Kit
  • Welcome to SaaS Starter Kit
  • Getting Started
    • Technology stack
    • Database Setup
    • Local Environment Setup
  • Basics
    • Dependencies
    • App architecture
    • Deployment
    • App roles
    • Endpoints List
      • Auth
      • Two Factor Auth
      • Businesses
      • Demo
      • Email
      • Export Document
      • Email Files
      • Files Demo
      • Leads
      • Orders
      • Payments
      • Subscriptions
      • Teams
      • Team Memberships
      • User Admin
  • Animation and Styles
    • Framer Motion
    • Ant Design and Styles
  • Pages
    • Auth
      • Working with PassportJS
      • Two-Factor Auth
      • OAuth Providers
    • Leads
    • Businesses
    • Team management
      • Ownership
    • Profile
    • User Settings
      • App Tour
    • App Settings
      • Lead Statuses
    • Dashboard
      • Lead volume widget
      • Doughnut chart widget
      • Recent leads table widget
      • Lead count over period widget
    • Demo
  • Features
    • Impersonation
    • Subscriptions (Stripe)
    • Search
    • Sentry
    • Captcha
    • Audit Logs
    • Internationalization
  • External integrations
    • Mailer
    • Google oAuth2
    • Facebook oAuth2
    • S3 compatible storage (AWS, MinIO)
Powered by GitBook
On this page
  • Comments
  • Getting logs and comments together in right order
  1. Pages

Businesses

Here you will find information about businesses, comments, infinite scroll lib

Like many other entities BusinessEntity connected to teamId, so only members of certain team will access to it. Also it connected @ManyToMany to LeadEntity so leads can be connected to many busineeses. Each business can have contactPerson field, which is @OnetoOne relation with TeamMembershipEntity. Relation isn't with UserEntity because each user can have many memberships which will be connected to different businesses.

BusinessEntity support:

  • Soft delete

  • Multi delete, restore, archive

  • Global search

  • CRUD

  • Photo CRUD

  • Audit logs

  • Comments

Business logs will record if a lead was assigned or unassigned to them.

Comments

On each business any member have ability to leave comments, delete and edit own comments. Each edit, delete action is monitored by audit logs, also each edited comment will have preposition "edited".

On frontend you can find logs and comments in BusinessPreview. All comments, logs sorted by createdAt field descend always. Both logs and comment are implemented with InfiniteScroll library.

Here you can see example of usage InfiniteScroll component:

                <div
                    id="scrollableDiv"
                    style={{
                        height: 408,
                        overflow: 'auto',
                    }}
                >
                    <InfiniteScroll
                        ref={infiniteScrollRef}
                        dataLength={businessLogs.length}
                        next={fetchLogs}
                        hasMore={hasMore}
                        height={408}
                        loader={
                            <Skeleton
                                avatar
                                paragraph={{
                                    rows: 1,
                                }}
                                active
                            />
                        }
                        onScroll={handleScroll}
                        style={{ scrollbarWidth: 'thin', scrollbarColor: '#888 #f1f1f1' }}
                    >
                        <LogsList logs={businessLogs} entityName={'businesses'} loading={loading} />
                    </InfiniteScroll>
                </div>

Props explanation:

  • ref - reference made with useRef() hook to have ability to scroll from code (to top for example)

  • dataLength - count of records used by lib to calculate optimal scroll height

  • next - function which is used to fetch next record when we scrolled to bottom enough

  • hasMore - bollean value which tells library if it is necessary to call next() function more

  • height - pixel height of scrollable container

  • loader - jsx which is shown at the bottom when we fetching records

  • handleScroll - fucntion which is called every time we are scrolling

  • style - css styling of container

For correct data fetching, we need to know how many records to skip, which can be determined by the number of records already on the page. Additionally, we need to keep the hasMore state updated. If the server doesn't send any records or sends fewer than requested, we can set hasMore to false. To maintain the correct order of records, we spread the previous logs and append the newly received records.

Code example:

const response = await getBusinessLogs(id, businessLogs.length, RECORD_LIMIT_PER_REQUEST);

            if (response.logs.length === 0 || response.logs.length < RECORD_LIMIT_PER_REQUEST) {
                setHasMore(false);
            }

            setBusinessLogs(prevLogs => [...prevLogs, ...response.logs]);

Getting logs and comments together in right order

To achieve the correct order by createdAt, we should fetch twice the requested number of records from both entities. This handles cases where, for example, we request 20 records (10 logs, 10 comments) but one entity has all 20 records created earlier than the other. We then combine the records into one array and sort them by createdAt. Afterward, we count the number of each record type to provide the correct count to the frontend. Finally, we slice the array to 20 records and return it.

Code example:

const logs = await this.auditLoggerService.findEntityLogs(
            AuditLogEntityTypes.Businesses,
            id,
            logsSkip,
            logsTake * 2
        );

const comments = await this.getBusinessComments(id, teamId, commentsSkip, commentsTake * 2);

const sortedLogsAndComments = [...logs.logs, ...comments.comments];

sortedLogsAndComments.sort((a, b) => dayjs(b.createdAt).valueOf() - dayjs(a.createdAt).valueOf());

let commentsCount = 0;
let logsCount = 0;

for (const item of sortedLogsAndComments.slice(0, 20)) {
    if ('action' in item) {
        logsCount++;
    } else {
        commentsCount++;
    }
}

return { logsAndComments: sortedLogsAndComments.slice(0, 20), logsCount, commentsCount };

Lead page has same logic with logs and comments

PreviousLeadsNextTeam management

Last updated 5 months ago