Files
dewedev/src/pages/ReleaseNotes.js
dwindown 04db088ff9 feat: Invoice Editor improvements and code cleanup
Major Invoice Editor updates:
-  Fixed tripled scrollbar issue by removing unnecessary overflow classes
-  Implemented dynamic currency system with JSON data loading
-  Fixed F4 PDF generation error with proper paper size handling
-  Added proper padding to Total section matching table headers
-  Removed print functionality (users can print from PDF download)
-  Streamlined preview toolbar: Back, Size selector, Download PDF
-  Fixed all ESLint warnings and errors
-  Removed console.log statements across codebase for cleaner production
-  Added border-top to Total section for better visual consistency
-  Improved print CSS and removed JSX warnings

Additional improvements:
- Added currencies.json to public folder for proper HTTP access
- Enhanced MinimalTemplate with better spacing and layout
- Clean build with no warnings or errors
- Updated release notes with new features
2025-09-28 00:09:06 +07:00

412 lines
16 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { Calendar, Sparkles, Bug, Zap, Shield, ChevronDown, ChevronUp } from 'lucide-react';
import ToolLayout from '../components/ToolLayout';
const ReleaseNotes = () => {
const [releases, setReleases] = useState([]);
const [loading, setLoading] = useState(true);
const [expandedReleases, setExpandedReleases] = useState(new Set());
// Parse commit messages into user-friendly release notes
const parseCommitMessage = (message) => {
// Skip non-user-informative commits
const skipPatterns = [
/^fix eslint/i,
/^remove.*eslint/i,
/^update.*package/i,
/^add debug/i,
/^fix.*dependency/i,
/deployment/i,
/^fix.*mismatch/i
];
if (skipPatterns.some(pattern => pattern.test(message))) {
return null;
}
// Transform commit messages to user-friendly descriptions
const transformations = [
{
pattern: /feat.*invoice.*editor.*improvements/i,
type: 'feature',
title: 'Invoice Editor Major Update',
description: 'Complete overhaul of Invoice Editor with currency system, PDF generation fixes, improved UI/UX, removed print functionality (use PDF download instead), streamlined preview toolbar, and comprehensive bug fixes'
},
{
pattern: /feat.*enhanced.*what.*new.*feature.*non_tools.*category.*global.*footer/i,
type: 'feature',
title: 'What\'s New Feature & Navigation Improvements',
description: 'Added attractive "What\'s New" button to homepage, created NON_TOOLS category for better navigation organization, separated navigation items in sidebar and mobile menu, and implemented unified global footer across all pages'
},
{
pattern: /improve.*objecteditor.*postmantable.*ui\/ux/i,
type: 'enhancement',
title: 'Enhanced Object Editor & Table View',
description: 'Improved user interface and experience with better JSON parsing, HTML rendering, and copy functionality'
},
{
pattern: /feat.*analytics.*mobile.*ui/i,
type: 'feature',
title: 'Mobile UI Improvements',
description: 'Optimized interface for mobile devices with better analytics integration'
},
{
pattern: /feat.*seo.*gdpr/i,
type: 'feature',
title: 'SEO & Privacy Compliance',
description: 'Comprehensive SEO optimization and GDPR compliance features for better discoverability and privacy protection'
},
{
pattern: /improve.*objecteditor.*tableeditor/i,
type: 'enhancement',
title: 'Enhanced Data Editors',
description: 'Major improvements to Object Editor and new Table Editor with advanced data manipulation features'
},
{
pattern: /enhanced.*object.*editor.*fetch.*mobile/i,
type: 'feature',
title: 'Object Editor with Data Fetching',
description: 'Added ability to fetch data from URLs directly in Object Editor with mobile-optimized interface'
},
{
pattern: /complete.*postman.*table.*view/i,
type: 'feature',
title: 'Postman-Style Table View',
description: 'New professional table visualization with consistent design and advanced data exploration features'
},
{
pattern: /enhanced.*mindmap.*visualization/i,
type: 'feature',
title: 'Professional Mindmap Visualization',
description: 'Beautiful mindmap interface for visualizing complex data structures with interactive navigation'
},
{
pattern: /add.*text.*length.*checker/i,
type: 'feature',
title: 'Text Analysis Tool',
description: 'New comprehensive text analysis tool with length checking and detailed text statistics'
},
{
pattern: /fix.*php.*serialization.*long.*text/i,
type: 'fix',
title: 'PHP Serialization Improvements',
description: 'Fixed PHP serialization handling and added support for long text fields in Visual Editor'
},
{
pattern: /enhanced.*developer.*tools.*ux/i,
type: 'enhancement',
title: 'Developer Tools UX Enhancement',
description: 'Improved overall user experience with visual enhancements and better tool organization'
}
];
for (const transform of transformations) {
if (transform.pattern.test(message)) {
return {
type: transform.type,
title: transform.title,
description: transform.description
};
}
}
// Fallback for unmatched patterns
if (message.includes('🐛') || message.toLowerCase().includes('fix')) {
return {
type: 'fix',
title: 'Bug Fixes',
description: message.replace(/🐛|fix/gi, '').trim()
};
}
if (message.includes('✨') || message.toLowerCase().includes('feat')) {
return {
type: 'feature',
title: 'New Feature',
description: message.replace(/✨|feat:/gi, '').trim()
};
}
return null;
};
// Get type icon and color
const getTypeConfig = (type) => {
const configs = {
feature: {
icon: <Sparkles className="h-4 w-4" />,
color: 'text-blue-600 dark:text-blue-400',
bgColor: 'bg-blue-100 dark:bg-blue-900/20',
label: 'New Feature'
},
enhancement: {
icon: <Zap className="h-4 w-4" />,
color: 'text-purple-600 dark:text-purple-400',
bgColor: 'bg-purple-100 dark:bg-purple-900/20',
label: 'Enhancement'
},
fix: {
icon: <Bug className="h-4 w-4" />,
color: 'text-green-600 dark:text-green-400',
bgColor: 'bg-green-100 dark:bg-green-900/20',
label: 'Bug Fix'
},
security: {
icon: <Shield className="h-4 w-4" />,
color: 'text-red-600 dark:text-red-400',
bgColor: 'bg-red-100 dark:bg-red-900/20',
label: 'Security'
}
};
return configs[type] || configs.enhancement;
};
// Group releases by date
const groupReleasesByDate = (releases) => {
const grouped = {};
releases.forEach(release => {
const date = new Date(release.date).toDateString();
if (!grouped[date]) {
grouped[date] = [];
}
grouped[date].push(release);
});
return grouped;
};
const toggleRelease = (date) => {
const newExpanded = new Set(expandedReleases);
if (newExpanded.has(date)) {
newExpanded.delete(date);
} else {
newExpanded.add(date);
}
setExpandedReleases(newExpanded);
};
useEffect(() => {
// Simulate fetching commit data (in real app, this would be an API call)
const commitData = [
{
hash: 'new2024',
date: '2025-09-24T18:57:18+07:00',
message: 'feat: Enhanced What\'s New feature with NON_TOOLS category and global footer'
},
{
hash: '21d0406e',
date: '2025-09-24T14:05:10+07:00',
message: 'Improve ObjectEditor and PostmanTable UI/UX'
},
{
hash: '57655410',
date: '2025-09-24T01:15:20+07:00',
message: 'feat: optimize analytics and mobile UI improvements'
},
{
hash: '2e67a2bc',
date: '2025-09-24T00:12:28+07:00',
message: 'feat: comprehensive SEO optimization and GDPR compliance'
},
{
hash: '977e784d',
date: '2025-09-23T14:17:13+07:00',
message: 'Improve ObjectEditor and Add TableEditor'
},
{
hash: 'e1c74e4a',
date: '2025-09-21T16:33:28+07:00',
message: '✨ Enhanced Object Editor with fetch data & mobile improvements'
},
{
hash: '12d45590',
date: '2025-09-21T15:09:17+07:00',
message: '🎯 Complete Postman-Style Table View with Consistent Design'
},
{
hash: '82d14622',
date: '2025-09-21T07:09:33+07:00',
message: '✨ Enhanced mindmap visualization with professional UI'
},
{
hash: '6f5bdf5f',
date: '2025-08-21T23:45:46+07:00',
message: 'Add Text Length Checker tool with comprehensive text analysis features'
},
{
hash: '65cc3bc5',
date: '2025-08-21T23:19:22+07:00',
message: 'Fix PHP serialization and add Long Text type to Visual Editor'
},
{
hash: '97459ea3',
date: '2025-08-07T20:05:11+07:00',
message: 'feat: Enhanced developer tools UX with visual improvements'
}
];
const parsedReleases = commitData
.map(commit => {
const parsed = parseCommitMessage(commit.message);
if (!parsed) return null;
return {
...parsed,
date: commit.date,
hash: commit.hash
};
})
.filter(Boolean);
setReleases(parsedReleases);
setLoading(false);
// Auto-expand only the first (latest) release
const groupedByDate = groupReleasesByDate(parsedReleases);
const sortedDates = Object.keys(groupedByDate).sort((a, b) => new Date(b) - new Date(a));
const autoExpand = new Set();
if (sortedDates.length > 0) {
autoExpand.add(sortedDates[0]); // Only expand the latest date
}
setExpandedReleases(autoExpand);
}, []);
const groupedReleases = groupReleasesByDate(releases);
return (
<ToolLayout
title=""
description=""
>
<div className="max-w-4xl mx-auto">
{/* Header */}
<div className="text-center mb-12">
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-2xl mb-6">
<Sparkles className="h-8 w-8 text-white" />
</div>
<h1 className="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">
What's New
</h1>
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
Discover the latest features, improvements, and bug fixes that make your development workflow even better.
</p>
</div>
{loading ? (
<div className="flex items-center justify-center py-12">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
</div>
) : (
<div className="relative">
{/* Timeline line */}
<div className="absolute left-8 top-0 bottom-0 w-0.5 bg-gradient-to-b from-blue-500 via-purple-500 to-transparent"></div>
<div className="space-y-6">
{Object.entries(groupedReleases)
.sort(([a], [b]) => new Date(b) - new Date(a))
.map(([date, dayReleases], index) => {
const isExpanded = expandedReleases.has(date);
const releaseDate = new Date(date);
const isRecent = (new Date() - releaseDate) < 7 * 24 * 60 * 60 * 1000;
return (
<div key={date} className="relative">
{/* Timeline dot */}
<div className="absolute left-6 top-6 w-4 h-4 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full border-4 border-white dark:border-gray-900 shadow-lg z-10"></div>
<div className="ml-16 bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
{/* Date Header */}
<button
onClick={() => toggleRelease(date)}
className="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
>
<div className="flex items-center space-x-3">
<Calendar className="h-5 w-5 text-gray-500 dark:text-gray-400" />
<div className="text-left">
<h3 className="font-semibold text-gray-900 dark:text-gray-100">
{releaseDate.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
{dayReleases.length} update{dayReleases.length !== 1 ? 's' : ''}
{isRecent && <span className="ml-2 text-blue-600 dark:text-blue-400">• Recent</span>}
</p>
</div>
</div>
{isExpanded ? (
<ChevronUp className="h-5 w-5 text-gray-400" />
) : (
<ChevronDown className="h-5 w-5 text-gray-400" />
)}
</button>
{/* Release Items */}
{isExpanded && (
<div className="border-t border-gray-200 dark:border-gray-700">
{dayReleases.map((release, index) => {
const typeConfig = getTypeConfig(release.type);
return (
<div key={release.hash} className={`p-6 ${index !== dayReleases.length - 1 ? 'border-b border-gray-100 dark:border-gray-700' : ''}`}>
<div className="flex flex-col md:flex-row items-start md:space-x-4">
<div className={`flex-shrink-0 p-2 rounded-lg ${typeConfig.bgColor} flex items-center space-x-2 mb-2`}>
<div className={typeConfig.color}>
{typeConfig.icon}
</div>
<span className={`block md:hidden px-2 py-1 text-xs font-medium rounded-full ${typeConfig.bgColor} ${typeConfig.color}`}>
{typeConfig.label}
</span>
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 mb-2">
<h4 className="font-semibold text-gray-900 dark:text-gray-100">
{release.title}
</h4>
<span className={`hidden md:block px-2 py-1 text-xs font-medium rounded-full ${typeConfig.bgColor} ${typeConfig.color}`}>
{typeConfig.label}
</span>
</div>
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
{release.description}
</p>
<div className="mt-3 flex items-center space-x-4 text-xs text-gray-500 dark:text-gray-400">
<span>
{new Date(release.date).toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit'
})}
</span>
<span>#{release.hash}</span>
</div>
</div>
</div>
</div>
);
})}
</div>
)}
</div>
</div>
);
})}
</div>
</div>
)}
{/* Footer */}
<div className="text-center mt-12 py-8 border-t border-gray-200 dark:border-gray-700">
<p className="text-gray-500 dark:text-gray-400">
Stay tuned for more exciting updates and improvements!
</p>
</div>
</div>
</ToolLayout>
);
};
export default ReleaseNotes;