Merge branch 'release/v2.0.3' of https://github.com/Worklenz/worklenz into feature/project-list-grouping

This commit is contained in:
chamikaJ
2025-06-13 13:02:57 +05:30
25 changed files with 1039 additions and 683 deletions

View File

@@ -68,7 +68,7 @@ const AccountStorage = ({ themeMode }: IAccountStorageProps) => {
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ padding: '0 16px' }}>
<Progress
percent={billingInfo?.usedPercentage ?? 0}
percent={billingInfo?.used_percent ?? 0}
type="circle"
format={percent => <span style={{ fontSize: '13px' }}>{percent}% Used</span>}
/>

View File

@@ -1,21 +1,17 @@
import { Button, Card, Col, Modal, Row, Tooltip, Typography } from 'antd';
import { Card, Col, Row, Tooltip, Typography } from 'antd';
import React, { useEffect } from 'react';
import './current-bill.css';
import { InfoCircleTwoTone } from '@ant-design/icons';
import ChargesTable from './billing-tables/charges-table';
import InvoicesTable from './billing-tables/invoices-table';
import UpgradePlansLKR from './drawers/upgrade-plans-lkr/upgrade-plans-lkr';
import UpgradePlans from './drawers/upgrade-plans/upgrade-plans';
import { useAppSelector } from '@/hooks/useAppSelector';
import { useAppDispatch } from '@/hooks/useAppDispatch';
import { useMediaQuery } from 'react-responsive';
import { useTranslation } from 'react-i18next';
import {
toggleDrawer,
toggleUpgradeModal,
} from '@/features/admin-center/billing/billing.slice';
import { fetchBillingInfo, fetchFreePlanSettings } from '@/features/admin-center/admin-center.slice';
import RedeemCodeDrawer from './drawers/redeem-code-drawer/redeem-code-drawer';
import CurrentPlanDetails from './current-plan-details/current-plan-details';
import AccountStorage from './account-storage/account-storage';
import { useAuthService } from '@/hooks/useAuth';
@@ -25,9 +21,7 @@ const CurrentBill: React.FC = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation('admin-center/current-bill');
const themeMode = useAppSelector(state => state.themeReducer.mode);
const { isUpgradeModalOpen } = useAppSelector(state => state.adminCenterReducer);
const isTablet = useMediaQuery({ query: '(min-width: 1025px)' });
const browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const currentSession = useAuthService().getCurrentSession();
useEffect(() => {
@@ -46,42 +40,7 @@ const CurrentBill: React.FC = () => {
const renderMobileView = () => (
<div>
<Col span={24}>
<Card
style={{ height: '100%' }}
title={<span style={titleStyle}>{t('currentPlanDetails')}</span>}
extra={
<div style={{ marginTop: '8px', marginRight: '8px' }}>
<Button type="primary" onClick={() => dispatch(toggleUpgradeModal())}>
{t('upgradePlan')}
</Button>
<Modal
open={isUpgradeModalOpen}
onCancel={() => dispatch(toggleUpgradeModal())}
width={1000}
centered
okButtonProps={{ hidden: true }}
cancelButtonProps={{ hidden: true }}
>
{browserTimeZone === 'Asia/Colombo' ? <UpgradePlansLKR /> : <UpgradePlans />}
</Modal>
</div>
}
>
<div style={{ display: 'flex', flexDirection: 'column', width: '50%', padding: '0 12px' }}>
<div style={{ marginBottom: '14px' }}>
<Typography.Text style={{ fontWeight: 700 }}>{t('cardBodyText01')}</Typography.Text>
<Typography.Text>{t('cardBodyText02')}</Typography.Text>
</div>
<Button
type="link"
style={{ margin: 0, padding: 0, width: '90px' }}
onClick={() => dispatch(toggleDrawer())}
>
{t('redeemCode')}
</Button>
<RedeemCodeDrawer />
</div>
</Card>
<CurrentPlanDetails />
</Col>
<Col span={24} style={{ marginTop: '1.5rem' }}>

View File

@@ -97,30 +97,28 @@ const InfoTabFooter = () => {
// mentions options
const mentionsOptions =
members?.map(member => ({
value: member.id,
value: member.name,
label: member.name,
key: member.id,
})) ?? [];
const memberSelectHandler = useCallback((member: IMentionMemberSelectOption) => {
console.log('member', member);
if (!member?.value || !member?.label) return;
// Find the member ID from the members list using the name
const selectedMember = members.find(m => m.name === member.value);
if (!selectedMember) return;
// Add to selected members if not already present
setSelectedMembers(prev =>
prev.some(mention => mention.team_member_id === member.value)
prev.some(mention => mention.team_member_id === selectedMember.id)
? prev
: [...prev, { team_member_id: member.value, name: member.label }]
: [...prev, { team_member_id: selectedMember.id!, name: selectedMember.name! }]
);
setCommentValue(prev => {
const parts = prev.split('@');
const lastPart = parts[parts.length - 1];
const mentionText = member.label;
// Keep only the part before the @ and add the new mention
return prev.slice(0, prev.length - lastPart.length) + mentionText;
});
}, []);
}, [members]);
const handleCommentChange = useCallback((value: string) => {
// Only update the value without trying to replace mentions
setCommentValue(value);
setCharacterLength(value.trim().length);
}, []);
@@ -275,6 +273,12 @@ const InfoTabFooter = () => {
maxLength={5000}
onClick={() => setIsCommentBoxExpand(true)}
onChange={e => setCharacterLength(e.length)}
prefix="@"
filterOption={(input, option) => {
if (!input) return true;
const optionLabel = (option as any)?.label || '';
return optionLabel.toLowerCase().includes(input.toLowerCase());
}}
style={{
minHeight: 60,
resize: 'none',
@@ -371,7 +375,11 @@ const InfoTabFooter = () => {
onSelect={option => memberSelectHandler(option as IMentionMemberSelectOption)}
onChange={handleCommentChange}
prefix="@"
split=""
filterOption={(input, option) => {
if (!input) return true;
const optionLabel = (option as any)?.label || '';
return optionLabel.toLowerCase().includes(input.toLowerCase());
}}
style={{
minHeight: 100,
maxHeight: 200,

View File

@@ -58,7 +58,7 @@ import alertService from '@/services/alerts/alertService';
interface ITaskAssignee {
id: string;
name: string;
name?: string;
email?: string;
avatar_url?: string;
team_member_id: string;