feat(email-templates): update release note template for Worklenz 2.1.0

- Added a title and meta subject for the release note template.
- Enhanced styling for better readability and user experience, including background color, font adjustments, and button styles.
- Introduced new sections for features, including a new tasks list, kanban board, group view, language support, and bug fixes.
- Improved responsiveness and dark mode support for the email template.
This commit is contained in:
chamikaJ
2025-07-08 11:59:17 +05:30
parent b0253135e5
commit a44b276269
4 changed files with 255 additions and 258 deletions

View File

@@ -45,7 +45,7 @@
// Determine which tracking ID to use based on the environment
const isProduction = window.location.hostname === 'app.worklenz.com';
const trackingId = isProduction ? 'G-XXXXXXXXXX' : 'G-3LM2HGWEXG'; // Open source tracking ID
const trackingId = isProduction ? 'G-7KSRKQ1397' : 'G-3LM2HGWEXG'; // Open source tracking ID
// Load the Google Analytics script
const script = document.createElement('script');

View File

@@ -26,7 +26,7 @@ const TASK_LIST_MIN_WIDTH = 500;
const SIDEBAR_MAX_WIDTH = 400;
// Lazy load heavy components
const TaskDrawer = React.lazy(() => import('@components/task-drawer/task-drawer'));
const TaskDrawer = React.lazy(() => import('@/components/task-drawer/task-drawer'));
const HomePage = memo(() => {
const dispatch = useAppDispatch();
@@ -35,6 +35,19 @@ const HomePage = memo(() => {
useDocumentTitle('Home');
// Preload TaskDrawer component to prevent dynamic import failures
useEffect(() => {
const preloadTaskDrawer = async () => {
try {
await import('@/components/task-drawer/task-drawer');
} catch (error) {
console.warn('Failed to preload TaskDrawer:', error);
}
};
preloadTaskDrawer();
}, []);
// Memoize fetch function to prevent recreation on every render
const fetchLookups = useCallback(async () => {
const fetchPromises = [
@@ -113,9 +126,15 @@ const HomePage = memo(() => {
{MainContent}
{/* Use Suspense for lazy-loaded components */}
<Suspense fallback={null}>
{createPortal(<TaskDrawer />, document.body, 'home-task-drawer')}
{/* Use Suspense for lazy-loaded components with error boundary */}
<Suspense fallback={<div>Loading...</div>}>
{createPortal(
<React.Suspense fallback={null}>
<TaskDrawer />
</React.Suspense>,
document.body,
'home-task-drawer'
)}
</Suspense>
{createPortal(

View File

@@ -379,6 +379,51 @@ const ProjectList: React.FC = () => {
}
}, [projectsError]);
// Optimized refresh handler with better error handling
const handleRefresh = useCallback(async () => {
try {
trackMixpanelEvent(evt_projects_refresh_click);
setIsLoading(true);
setErrorMessage(null);
if (viewMode === ProjectViewType.LIST) {
await refetchProjects();
} else if (viewMode === ProjectViewType.GROUP && groupBy) {
await dispatch(fetchGroupedProjects(groupedRequestParams)).unwrap();
}
} catch (error) {
console.error('Error refreshing projects:', error);
setErrorMessage('Failed to refresh projects. Please try again.');
} finally {
setIsLoading(false);
}
}, [trackMixpanelEvent, refetchProjects, viewMode, groupBy, dispatch, groupedRequestParams]);
// Enhanced empty text with error handling
const emptyContent = useMemo(() => {
if (errorMessage) {
return (
<Empty
description={
<div>
<p>{errorMessage}</p>
<Button type="primary" onClick={handleRefresh} loading={isLoading}>
Retry
</Button>
</div>
}
/>
);
}
return <Empty description={t('noProjects')} />;
}, [errorMessage, handleRefresh, isLoading, t]);
// Memoize the pagination show total function
const paginationShowTotal = useMemo(
() => (total: number, range: [number, number]) => `${range[0]}-${range[1]} of ${total} groups`,
[]
);
const handleTableChange = useCallback(
(
newPagination: TablePaginationConfig,