Files
dewedev/src/pages/ReleaseNotes.js
dwindown 78570f04f0 feat: Enhanced release notes system, fixed invoice installments, and improved logo integration
- Updated release notes to use new JSON structure with individual commit timestamps
- Removed hash display from release notes for cleaner UI
- Fixed automatic recalculation of percentage-based installments in Invoice Editor and Preview
- Integrated custom logo.svg in header and footer with cleaner styling
- Moved all data files to /public/data/ for better organization
- Cleaned up unused release data files and improved file structure
2025-09-28 17:14:54 +07:00

359 lines
14 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 (keeping local version for now)
// eslint-disable-next-line no-unused-vars
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(() => {
// Load release data from commits.json
const fetchReleases = async () => {
setLoading(true);
try {
const response = await fetch('/data/commits.json');
const data = await response.json();
// Transform changelog data to release format
const releases = [];
data.changelog.forEach(dateEntry => {
dateEntry.changes.forEach(change => {
releases.push({
id: `${dateEntry.date}-${change.type}-${change.title.replace(/\s+/g, '-')}`,
date: change.datetime || dateEntry.date, // Use datetime if available, fallback to date
type: change.type,
title: change.title,
description: change.description
});
});
});
setReleases(releases);
} catch (error) {
console.error('Failed to load commits.json:', error);
setReleases([]);
} finally {
setLoading(false);
}
};
fetchReleases();
}, []);
const groupedReleases = groupReleasesByDate(releases);
return (
<ToolLayout
title="What's New"
description="Stay updated with the latest features, improvements, and bug fixes"
>
<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>
</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;