courrier refactor rebuild 2
This commit is contained in:
parent
b036530766
commit
a51a4c303d
@ -216,3 +216,42 @@
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* Quill editor customizations for email composition */
|
||||
.ql-editor {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Quote formatting for forwarded/replied emails */
|
||||
.ql-editor blockquote {
|
||||
border-left: 3px solid #ddd;
|
||||
padding-left: 10px;
|
||||
margin: 8px 0;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/* Forward message formatting */
|
||||
.ql-editor .forward-header {
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* Make sure the quoted content is properly indented */
|
||||
.ql-editor .email-original-content {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Fix toolbar button styling */
|
||||
.ql-toolbar.ql-snow {
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.ql-container.ql-snow {
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ import { Label } from '@/components/ui/label';
|
||||
import ComposeEmailHeader from './ComposeEmailHeader';
|
||||
import ComposeEmailForm from './ComposeEmailForm';
|
||||
import ComposeEmailFooter from './ComposeEmailFooter';
|
||||
import RichEmailEditor from './RichEmailEditor';
|
||||
|
||||
// Import ONLY from the centralized formatter
|
||||
import {
|
||||
@ -332,20 +333,12 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
||||
{/* Message Body */}
|
||||
<div className="flex-1 min-h-[200px] flex flex-col">
|
||||
<Label htmlFor="message" className="flex-none block text-sm font-medium text-gray-700 mb-2">Message</Label>
|
||||
<div className="flex-1 flex flex-col border border-gray-300 rounded-md overflow-hidden">
|
||||
<div
|
||||
className="flex-1 w-full bg-white p-4 text-black overflow-y-auto email-content-display"
|
||||
style={{
|
||||
minHeight: '200px',
|
||||
maxHeight: 'calc(100vh - 400px)'
|
||||
}}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: emailContent }} />
|
||||
</div>
|
||||
<textarea
|
||||
className="hidden"
|
||||
value={emailContent}
|
||||
onChange={(e) => setEmailContent(e.target.value)}
|
||||
<div className="flex-1 border border-gray-300 rounded-md overflow-hidden">
|
||||
<RichEmailEditor
|
||||
initialContent={emailContent}
|
||||
onChange={setEmailContent}
|
||||
minHeight="200px"
|
||||
maxHeight="calc(100vh - 400px)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -626,20 +619,12 @@ function LegacyAdapter({
|
||||
{/* Message Body */}
|
||||
<div className="flex-1 min-h-[200px] flex flex-col">
|
||||
<Label htmlFor="message" className="flex-none block text-sm font-medium text-gray-700 mb-2">Message</Label>
|
||||
<div className="flex-1 flex flex-col border border-gray-300 rounded-md overflow-hidden">
|
||||
<div
|
||||
className="flex-1 w-full bg-white p-4 text-black overflow-y-auto email-content-display"
|
||||
style={{
|
||||
minHeight: '200px',
|
||||
maxHeight: 'calc(100vh - 400px)'
|
||||
}}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: composeBody }} />
|
||||
</div>
|
||||
<textarea
|
||||
className="hidden"
|
||||
value={composeBody}
|
||||
onChange={(e) => setComposeBody(e.target.value)}
|
||||
<div className="flex-1 border border-gray-300 rounded-md overflow-hidden">
|
||||
<RichEmailEditor
|
||||
initialContent={composeBody}
|
||||
onChange={setComposeBody}
|
||||
minHeight="200px"
|
||||
maxHeight="calc(100vh - 400px)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
132
components/email/RichEmailEditor.tsx
Normal file
132
components/email/RichEmailEditor.tsx
Normal file
@ -0,0 +1,132 @@
|
||||
'use client';
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import 'quill/dist/quill.snow.css';
|
||||
import { sanitizeHtml } from '@/lib/utils/email-formatter';
|
||||
|
||||
interface RichEmailEditorProps {
|
||||
initialContent: string;
|
||||
onChange: (content: string) => void;
|
||||
placeholder?: string;
|
||||
minHeight?: string;
|
||||
maxHeight?: string;
|
||||
}
|
||||
|
||||
const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
||||
initialContent,
|
||||
onChange,
|
||||
placeholder = 'Write your message here...',
|
||||
minHeight = '200px',
|
||||
maxHeight = 'calc(100vh - 400px)',
|
||||
}) => {
|
||||
const editorRef = useRef<HTMLDivElement>(null);
|
||||
const quillRef = useRef<any>(null);
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
// Initialize Quill editor when component mounts
|
||||
useEffect(() => {
|
||||
// Import Quill dynamically (client-side only)
|
||||
const initializeQuill = async () => {
|
||||
if (!editorRef.current) return;
|
||||
|
||||
const Quill = (await import('quill')).default;
|
||||
|
||||
// Define custom formats/modules as needed for email
|
||||
const emailToolbarOptions = [
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||
[{ 'indent': '-1'}, { 'indent': '+1' }],
|
||||
[{ 'align': [] }],
|
||||
['link'],
|
||||
['clean'],
|
||||
];
|
||||
|
||||
// Create new Quill instance with the DOM element
|
||||
const editorElement = editorRef.current;
|
||||
quillRef.current = new Quill(editorElement, {
|
||||
modules: {
|
||||
toolbar: emailToolbarOptions
|
||||
},
|
||||
placeholder: placeholder,
|
||||
theme: 'snow',
|
||||
});
|
||||
|
||||
// Set initial content (sanitized)
|
||||
if (initialContent) {
|
||||
quillRef.current.clipboard.dangerouslyPasteHTML(sanitizeHtml(initialContent));
|
||||
}
|
||||
|
||||
// Add change listener
|
||||
quillRef.current.on('text-change', () => {
|
||||
const html = quillRef.current.root.innerHTML;
|
||||
onChange(html);
|
||||
});
|
||||
|
||||
setIsReady(true);
|
||||
};
|
||||
|
||||
initializeQuill();
|
||||
|
||||
// Clean up on unmount
|
||||
return () => {
|
||||
if (quillRef.current) {
|
||||
// Clean up any event listeners or resources
|
||||
quillRef.current.off('text-change');
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Update content from props if changed externally
|
||||
useEffect(() => {
|
||||
if (quillRef.current && isReady) {
|
||||
const currentContent = quillRef.current.root.innerHTML;
|
||||
if (initialContent !== currentContent) {
|
||||
quillRef.current.clipboard.dangerouslyPasteHTML(sanitizeHtml(initialContent));
|
||||
}
|
||||
}
|
||||
}, [initialContent, isReady]);
|
||||
|
||||
return (
|
||||
<div className="rich-email-editor-container">
|
||||
{/* Quill container */}
|
||||
<div
|
||||
ref={editorRef}
|
||||
className="quill-editor"
|
||||
style={{
|
||||
height: 'auto',
|
||||
minHeight: minHeight,
|
||||
maxHeight: maxHeight
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Loading indicator */}
|
||||
{!isReady && (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Custom styles for email context */}
|
||||
<style jsx>{`
|
||||
.rich-email-editor-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
.quill-editor {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Hide the editor until it's ready */
|
||||
.quill-editor ${!isReady ? '{ display: none; }' : ''}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RichEmailEditor;
|
||||
@ -9,6 +9,8 @@
|
||||
*/
|
||||
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
import { formatDateRelative } from './date-formatter';
|
||||
|
||||
// Reset any existing hooks to start clean
|
||||
DOMPurify.removeAllHooks();
|
||||
@ -364,4 +366,71 @@ export function encodeComposeContent(content: string): string {
|
||||
return Object.entries(mimeHeaders)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join('\n') + '\n\n' + content;
|
||||
}
|
||||
|
||||
// Email formatter functions for various email actions
|
||||
export function formatReplyEmail(email: any): string {
|
||||
const originalSender = email.sender?.name || email.sender?.email || 'Unknown Sender';
|
||||
const originalDate = formatDateRelative(new Date(email.date));
|
||||
|
||||
const sanitizedBody = sanitizeHtml(email.content || '', {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||
allowedAttributes: {
|
||||
...sanitizeHtml.defaults.allowedAttributes,
|
||||
img: ['src', 'alt', 'width', 'height']
|
||||
}
|
||||
});
|
||||
|
||||
return `
|
||||
<p></p>
|
||||
<p>On ${originalDate}, ${originalSender} wrote:</p>
|
||||
<blockquote class="quoted-content">
|
||||
${sanitizedBody}
|
||||
</blockquote>
|
||||
`.trim();
|
||||
}
|
||||
|
||||
export function formatForwardedEmail(email: any): string {
|
||||
const originalSender = email.sender?.name || email.sender?.email || 'Unknown Sender';
|
||||
const originalRecipients = email.to?.map((recipient: any) =>
|
||||
recipient.name || recipient.email
|
||||
).join(', ') || 'Unknown Recipients';
|
||||
const originalDate = formatDateRelative(new Date(email.date));
|
||||
const originalSubject = email.subject || 'No Subject';
|
||||
|
||||
const sanitizedBody = sanitizeHtml(email.content || '', {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||
allowedAttributes: {
|
||||
...sanitizeHtml.defaults.allowedAttributes,
|
||||
img: ['src', 'alt', 'width', 'height']
|
||||
}
|
||||
});
|
||||
|
||||
return `
|
||||
<p></p>
|
||||
<p>---------- Forwarded message ---------</p>
|
||||
<p><strong>From:</strong> ${originalSender}</p>
|
||||
<p><strong>Date:</strong> ${originalDate}</p>
|
||||
<p><strong>Subject:</strong> ${originalSubject}</p>
|
||||
<p><strong>To:</strong> ${originalRecipients}</p>
|
||||
<br>
|
||||
<div class="email-original-content">
|
||||
${sanitizedBody}
|
||||
</div>
|
||||
`.trim();
|
||||
}
|
||||
|
||||
export function formatReplyToAllEmail(email: any): string {
|
||||
// For reply all, we use the same format as regular reply
|
||||
return formatReplyEmail(email);
|
||||
}
|
||||
|
||||
// Utility function to get the reply subject line
|
||||
export function getReplySubject(subject: string): string {
|
||||
return subject.startsWith('Re:') ? subject : `Re: ${subject}`;
|
||||
}
|
||||
|
||||
// Utility function to get the forward subject line
|
||||
export function getForwardSubject(subject: string): string {
|
||||
return subject.startsWith('Fwd:') ? subject : `Fwd: ${subject}`;
|
||||
}
|
||||
66
node_modules/.package-lock.json
generated
vendored
66
node_modules/.package-lock.json
generated
vendored
@ -3584,6 +3584,12 @@
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
},
|
||||
"node_modules/fast-diff": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
|
||||
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/fast-equals": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz",
|
||||
@ -4472,6 +4478,18 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
@ -4479,6 +4497,13 @@
|
||||
"deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@ -4955,6 +4980,12 @@
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"node_modules/parchment": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz",
|
||||
"integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
|
||||
@ -5576,6 +5607,41 @@
|
||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quill": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz",
|
||||
"integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^5.0.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"parchment": "^3.0.0",
|
||||
"quill-delta": "^5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=8.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/quill-delta": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
|
||||
"integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-diff": "^1.3.0",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.isequal": "^4.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/quill/node_modules/eventemitter3": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quoted-printable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/quoted-printable/-/quoted-printable-1.0.1.tgz",
|
||||
|
||||
67
package-lock.json
generated
67
package-lock.json
generated
@ -70,6 +70,7 @@
|
||||
"next-themes": "^0.4.4",
|
||||
"nodemailer": "^6.10.1",
|
||||
"pg": "^8.14.1",
|
||||
"quill": "^2.0.3",
|
||||
"react": "^18",
|
||||
"react-datepicker": "^8.3.0",
|
||||
"react-day-picker": "8.10.1",
|
||||
@ -4552,6 +4553,12 @@
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
},
|
||||
"node_modules/fast-diff": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
|
||||
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/fast-equals": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz",
|
||||
@ -5440,6 +5447,18 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
@ -5447,6 +5466,13 @@
|
||||
"deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@ -5923,6 +5949,12 @@
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"node_modules/parchment": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz",
|
||||
"integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
|
||||
@ -6544,6 +6576,41 @@
|
||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quill": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz",
|
||||
"integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^5.0.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"parchment": "^3.0.0",
|
||||
"quill-delta": "^5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=8.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/quill-delta": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz",
|
||||
"integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-diff": "^1.3.0",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.isequal": "^4.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/quill/node_modules/eventemitter3": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quoted-printable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/quoted-printable/-/quoted-printable-1.0.1.tgz",
|
||||
|
||||
@ -71,6 +71,7 @@
|
||||
"next-themes": "^0.4.4",
|
||||
"nodemailer": "^6.10.1",
|
||||
"pg": "^8.14.1",
|
||||
"quill": "^2.0.3",
|
||||
"react": "^18",
|
||||
"react-datepicker": "^8.3.0",
|
||||
"react-day-picker": "8.10.1",
|
||||
|
||||
49
yarn.lock
49
yarn.lock
@ -1835,6 +1835,16 @@ eventemitter3@^4.0.1:
|
||||
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz"
|
||||
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
|
||||
|
||||
eventemitter3@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz"
|
||||
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
|
||||
|
||||
fast-diff@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz"
|
||||
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
|
||||
|
||||
fast-equals@^5.0.1:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz"
|
||||
@ -2355,11 +2365,26 @@ linkify-it@5.0.0:
|
||||
dependencies:
|
||||
uc.micro "^2.0.0"
|
||||
|
||||
lodash-es@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
|
||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||
|
||||
lodash.clonedeep@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
|
||||
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz"
|
||||
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
|
||||
|
||||
lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz"
|
||||
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
|
||||
|
||||
lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||
@ -2647,6 +2672,11 @@ package-json-from-dist@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz"
|
||||
integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
|
||||
|
||||
parchment@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz"
|
||||
integrity sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==
|
||||
|
||||
parse5@^7.0.0, parse5@^7.2.1:
|
||||
version "7.2.1"
|
||||
resolved "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz"
|
||||
@ -3001,6 +3031,25 @@ quick-format-unescaped@^4.0.3:
|
||||
resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz"
|
||||
integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==
|
||||
|
||||
quill-delta@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz"
|
||||
integrity sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==
|
||||
dependencies:
|
||||
fast-diff "^1.3.0"
|
||||
lodash.clonedeep "^4.5.0"
|
||||
lodash.isequal "^4.5.0"
|
||||
|
||||
quill@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz"
|
||||
integrity sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==
|
||||
dependencies:
|
||||
eventemitter3 "^5.0.1"
|
||||
lodash-es "^4.17.21"
|
||||
parchment "^3.0.0"
|
||||
quill-delta "^5.1.0"
|
||||
|
||||
quoted-printable@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/quoted-printable/-/quoted-printable-1.0.1.tgz"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user