Merge branch 'main' into patch-3
This commit is contained in:
commit
61015ff99d
3
.gitignore
vendored
3
.gitignore
vendored
@ -66,9 +66,6 @@ typings/
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# direnv
|
||||
.direnv
|
||||
|
||||
# IDE
|
||||
.idea/*
|
||||
*.iml
|
||||
|
@ -4,7 +4,7 @@ import articleBodyStyles from './articleBodyStyles';
|
||||
import getUsername from '../utils/get-username';
|
||||
import {ActivityPubAPI} from '../api/activitypub';
|
||||
import {ActorProperties, ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
||||
import {Avatar, Button, ButtonGroup, Heading, List, ListItem, Page, SelectOption, SettingValue, ViewContainer, ViewTab} from '@tryghost/admin-x-design-system';
|
||||
import {Avatar, Button, ButtonGroup, Heading, Icon, List, ListItem, Page, SelectOption, SettingValue, ViewContainer, ViewTab} from '@tryghost/admin-x-design-system';
|
||||
import {useBrowseSite} from '@tryghost/admin-x-framework/api/site';
|
||||
import {useQuery} from '@tanstack/react-query';
|
||||
import {useRouting} from '@tryghost/admin-x-framework/routing';
|
||||
@ -123,6 +123,7 @@ const ActivityPubComponent: React.FC = () => {
|
||||
actor={activity.actor}
|
||||
layout={selectedOption.value}
|
||||
object={activity.object}
|
||||
type={activity.type}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
@ -167,6 +168,7 @@ const ActivityPubComponent: React.FC = () => {
|
||||
actor={activity.actor}
|
||||
layout={selectedOption.value}
|
||||
object={activity.object}
|
||||
type={activity.object.type}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
@ -320,7 +322,7 @@ ${image &&
|
||||
);
|
||||
};
|
||||
|
||||
const ObjectContentDisplay: React.FC<{actor: ActorProperties, object: ObjectProperties, layout: string }> = ({actor, object, layout}) => {
|
||||
const ObjectContentDisplay: React.FC<{actor: ActorProperties, object: ObjectProperties, layout: string, type: string }> = ({actor, object, layout, type}) => {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(object.content || '', 'text/html');
|
||||
|
||||
@ -392,27 +394,40 @@ const ObjectContentDisplay: React.FC<{actor: ActorProperties, object: ObjectProp
|
||||
setTimeout(() => setIsClicked(false), 300); // Reset the animation class after 300ms
|
||||
};
|
||||
|
||||
let author = actor;
|
||||
if (type === 'Announce' && object.type === 'Note') {
|
||||
author = typeof object.attributedTo === 'object' ? object.attributedTo as ActorProperties : actor;
|
||||
}
|
||||
|
||||
if (layout === 'feed') {
|
||||
return (
|
||||
<>
|
||||
{object && (
|
||||
<div className='group/article relative flex cursor-pointer items-start gap-4 pt-4'>
|
||||
<img className='z-10 w-9 rounded' src={actor.icon?.url}/>
|
||||
<div className='border-1 z-10 -mt-1 flex flex-col items-start justify-between border-b border-b-grey-200 pb-4' data-test-activity>
|
||||
<div className='relative z-10 flex w-full overflow-visible text-[1.5rem]'>
|
||||
<p className='mr-1 truncate whitespace-nowrap font-bold' data-test-activity-heading>{actor.name}</p>
|
||||
<span className='truncate text-grey-700'>{getUsername(actor)}</span>
|
||||
<span className='whitespace-nowrap text-grey-700 before:mx-1 before:content-["·"]'>{timestamp}</span>
|
||||
</div>
|
||||
<div className='relative z-10 w-full gap-4'>
|
||||
<div className='flex flex-col'>
|
||||
{object.name && <Heading className='mb-1 leading-tight' level={4} data-test-activity-heading>{object.name}</Heading>}
|
||||
<p className='text-pretty text-[1.5rem] text-grey-900'>{plainTextContent}</p>
|
||||
{/* <p className='text-pretty text-md text-grey-900'>{object.content}</p> */}
|
||||
{renderAttachment()}
|
||||
<div className='mt-3 flex gap-2'>
|
||||
<Button className={`self-start text-grey-500 transition-all hover:text-grey-800 ${isClicked ? 'bump' : ''} ${isLiked ? 'ap-red-heart text-red *:!fill-red hover:text-red' : ''}`} hideLabel={true} icon='heart' id="like" size='md' unstyled={true} onClick={handleLikeClick}/>
|
||||
<span className={`text-grey-800 ${isLiked ? 'opacity-100' : 'opacity-0'}`}>1</span>
|
||||
<div className='group/article relative cursor-pointer pt-4'>
|
||||
{(type === 'Announce' && object.type === 'Note') && <div className='z-10 mb-2 flex items-center gap-4 text-grey-700'>
|
||||
<div className='z-10 flex w-10 justify-end'><Icon colorClass='text-grey-700' name='reload' size={'sm'}></Icon></div>
|
||||
<span className='z-10'>{actor.name} reposted</span>
|
||||
</div>}
|
||||
<div className='flex items-start gap-4'>
|
||||
<img className='z-10 w-10 rounded' src={author.icon?.url}/>
|
||||
<div className='border-1 z-10 -mt-1 flex flex-col items-start justify-between border-b border-b-grey-200 pb-4' data-test-activity>
|
||||
<div className='relative z-10 mb-2 flex w-full flex-col overflow-visible text-[1.5rem]'>
|
||||
<span className='mr-1 truncate whitespace-nowrap font-bold' data-test-activity-heading>{author.name}</span>
|
||||
<div className='flex'>
|
||||
<span className='truncate text-grey-700'>{getUsername(author)}</span>
|
||||
<span className='whitespace-nowrap text-grey-700 before:mx-1 before:content-["·"]'>{timestamp}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='relative z-10 w-full gap-4'>
|
||||
<div className='flex flex-col'>
|
||||
{object.name && <Heading className='mb-1 leading-tight' level={4} data-test-activity-heading>{object.name}</Heading>}
|
||||
<div dangerouslySetInnerHTML={({__html: object.content})} className='ap-note-content text-pretty text-[1.5rem] text-grey-900'></div>
|
||||
{/* <p className='text-pretty text-md text-grey-900'>{object.content}</p> */}
|
||||
{renderAttachment()}
|
||||
<div className='mt-3 flex gap-2'>
|
||||
<Button className={`self-start text-grey-500 transition-all hover:text-grey-800 ${isClicked ? 'bump' : ''} ${isLiked ? 'ap-red-heart text-red *:!fill-red hover:text-red' : ''}`} hideLabel={true} icon='heart' id="like" size='md' unstyled={true} onClick={handleLikeClick}/>
|
||||
<span className={`text-grey-800 ${isLiked ? 'opacity-100' : 'opacity-0'}`}>1</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -22,4 +22,17 @@ animation: bump 0.3s ease-in-out;
|
||||
|
||||
.ap-red-heart path {
|
||||
fill: #F50B23;
|
||||
}
|
||||
}
|
||||
|
||||
.ap-note-content a {
|
||||
color: rgb(236 72 153) !important;
|
||||
}
|
||||
|
||||
.ap-note-content a:hover {
|
||||
color: rgb(219 39 119) !important;
|
||||
}
|
||||
|
||||
.ap-note-content p + p {
|
||||
margin-top: 1.5rem !important;
|
||||
}
|
||||
|
||||
|
1
apps/admin-x-design-system/src/assets/icons/reload.svg
Normal file
1
apps/admin-x-design-system/src/assets/icons/reload.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="Button-Refresh-Arrows--Streamline-Ultimate.svg" height="24" width="24"><desc>Button Refresh Arrows Streamline Icon: https://streamlinehq.com</desc><path d="m5.25 14.248 0 4.5 -4.5 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"></path><path d="m18.75 9.748 0 -4.5 4.5 0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"></path><path d="M19.032 5.245A9.752 9.752 0 0 1 8.246 21" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"></path><path d="M4.967 18.751A9.753 9.753 0 0 1 15.754 3" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"></path></svg>
|
After Width: | Height: | Size: 819 B |
@ -13,7 +13,7 @@ export type ObjectProperties = {
|
||||
name: string;
|
||||
content: string;
|
||||
url?: string | undefined;
|
||||
attributedTo?: string | object[] | undefined;
|
||||
attributedTo?: object | string | object[] | undefined;
|
||||
image?: string;
|
||||
published?: string;
|
||||
preview?: {type: string, content: string};
|
||||
|
@ -44,16 +44,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "1.7.19",
|
||||
"@tiptap/core": "2.5.8",
|
||||
"@tiptap/extension-blockquote": "2.5.8",
|
||||
"@tiptap/extension-document": "2.5.8",
|
||||
"@tiptap/extension-hard-break": "2.5.8",
|
||||
"@tiptap/extension-link": "2.5.8",
|
||||
"@tiptap/extension-paragraph": "2.5.8",
|
||||
"@tiptap/extension-placeholder": "2.5.8",
|
||||
"@tiptap/extension-text": "2.5.8",
|
||||
"@tiptap/pm": "2.5.8",
|
||||
"@tiptap/react": "2.5.8",
|
||||
"@tiptap/core": "2.5.9",
|
||||
"@tiptap/extension-blockquote": "2.5.9",
|
||||
"@tiptap/extension-document": "2.5.9",
|
||||
"@tiptap/extension-hard-break": "2.5.9",
|
||||
"@tiptap/extension-link": "2.5.9",
|
||||
"@tiptap/extension-paragraph": "2.5.9",
|
||||
"@tiptap/extension-placeholder": "2.5.9",
|
||||
"@tiptap/extension-text": "2.5.9",
|
||||
"@tiptap/pm": "2.5.9",
|
||||
"@tiptap/react": "2.5.9",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-string-replace": "1.1.1"
|
||||
|
43
flake.lock
43
flake.lock
@ -1,43 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1708501555,
|
||||
"narHash": "sha256-zJaF0RkdIPbh8LTmnpW/E7tZYpqIE+MePzlWwUNob4c=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b50a77c03d640716296021ad58950b1bb0345799",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
49
flake.nix
49
flake.nix
@ -1,49 +0,0 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
systems,
|
||||
nixpkgs,
|
||||
...
|
||||
} @ inputs: let
|
||||
yarn_overlay = final: prev: {
|
||||
yarn = prev.yarn.overrideAttrs(finalAttrs: prevAttrs: {
|
||||
# This is to make sure that yarn runs the correct node version
|
||||
# https://github.com/NixOS/nixpkgs/issues/145634#issuecomment-1627476963
|
||||
installPhase = prevAttrs.installPhase + ''
|
||||
ln -fs $out/libexec/yarn/bin/yarn $out/bin/yarn
|
||||
ln -fs $out/libexec/yarn/bin/yarn.js $out/bin/yarn.js
|
||||
ln -fs $out/libexec/yarn/bin/yarn $out/bin/yarnpkg
|
||||
'';
|
||||
});
|
||||
};
|
||||
|
||||
# This gives us a central place to set the node version
|
||||
node_overlay = final: prev: {
|
||||
nodejs = prev.nodejs-18_x;
|
||||
};
|
||||
|
||||
eachSystem = f:
|
||||
nixpkgs.lib.genAttrs (import systems) (
|
||||
system:
|
||||
f ((nixpkgs.legacyPackages.${system}.extend yarn_overlay).extend node_overlay)
|
||||
);
|
||||
in {
|
||||
|
||||
devShells = eachSystem (pkgs: {
|
||||
default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
nodejs
|
||||
yarn
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "node `${pkgs.nodejs}/bin/node --version`"
|
||||
'';
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
@ -24,6 +24,6 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2"
|
||||
"@tryghost/errors": "1.3.5"
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,9 @@
|
||||
@placeholder={{@bodyPlaceholder}}
|
||||
@cardConfig={{@cardOptions}}
|
||||
@onChange={{@onBodyChange}}
|
||||
@updateSecondaryInstanceModel={{@updateSecondaryInstanceModel}}
|
||||
@registerAPI={{this.registerEditorAPI}}
|
||||
@registerSecondaryAPI={{this.registerSecondaryEditorAPI}}
|
||||
@cursorDidExitAtTop={{if this.feature.editorExcerpt this.focusExcerpt this.focusTitle}}
|
||||
@updateWordCount={{@updateWordCount}}
|
||||
@updatePostTkCount={{@updatePostTkCount}}
|
||||
|
@ -15,6 +15,7 @@ export default class GhKoenigEditorLexical extends Component {
|
||||
uploadUrl = `${ghostPaths().apiRoot}/images/upload/`;
|
||||
|
||||
editorAPI = null;
|
||||
secondaryEditorAPI = null;
|
||||
skipFocusEditor = false;
|
||||
|
||||
@tracked titleIsHovered = false;
|
||||
@ -232,6 +233,12 @@ export default class GhKoenigEditorLexical extends Component {
|
||||
this.args.registerAPI(API);
|
||||
}
|
||||
|
||||
@action
|
||||
registerSecondaryEditorAPI(API) {
|
||||
this.secondaryEditorAPI = API;
|
||||
this.args.registerSecondaryAPI(API);
|
||||
}
|
||||
|
||||
// focus the editor when the editor canvas is clicked below the editor content,
|
||||
// otherwise the browser will defocus the editor and the cursor will disappear
|
||||
@action
|
||||
|
@ -853,6 +853,7 @@
|
||||
post=this.post
|
||||
editorAPI=this.editorAPI
|
||||
toggleSettingsMenu=this.toggleSettingsMenu
|
||||
secondaryEditorAPI=this.secondaryEditorAPI
|
||||
}}
|
||||
@close={{this.closePostHistory}}
|
||||
@modifier="total-overlay post-history" />
|
||||
|
@ -669,34 +669,43 @@ export default class KoenigLexicalEditor extends Component {
|
||||
const multiplayerDocId = cardConfig.post.id;
|
||||
const multiplayerUsername = this.session.user.name;
|
||||
|
||||
const KGEditorComponent = ({isInitInstance}) => {
|
||||
return (
|
||||
<div style={isInitInstance ? {visibility: 'hidden', position: 'absolute'} : {}}>
|
||||
<KoenigComposer
|
||||
editorResource={this.editorResource}
|
||||
cardConfig={cardConfig}
|
||||
enableMultiplayer={enableMultiplayer}
|
||||
fileUploader={{useFileUpload, fileTypes}}
|
||||
initialEditorState={this.args.lexical}
|
||||
multiplayerUsername={multiplayerUsername}
|
||||
multiplayerDocId={multiplayerDocId}
|
||||
multiplayerEndpoint={multiplayerEndpoint}
|
||||
onError={this.onError}
|
||||
darkMode={this.feature.nightShift}
|
||||
isTKEnabled={true}
|
||||
>
|
||||
<KoenigEditor
|
||||
editorResource={this.editorResource}
|
||||
cursorDidExitAtTop={isInitInstance ? null : this.args.cursorDidExitAtTop}
|
||||
placeholderText={isInitInstance ? null : this.args.placeholderText}
|
||||
darkMode={isInitInstance ? null : this.feature.nightShift}
|
||||
onChange={isInitInstance ? this.args.updateSecondaryInstanceModel : this.args.onChange}
|
||||
registerAPI={isInitInstance ? this.args.registerSecondaryAPI : this.args.registerAPI}
|
||||
/>
|
||||
<WordCountPlugin editorResource={this.editorResource} onChange={isInitInstance ? () => {} : this.args.updateWordCount} />
|
||||
<TKCountPlugin editorResource={this.editorResource} onChange={isInitInstance ? () => {} : this.args.updatePostTkCount} />
|
||||
</KoenigComposer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={['koenig-react-editor', 'koenig-lexical', this.args.className].filter(Boolean).join(' ')}>
|
||||
<ErrorHandler config={this.config}>
|
||||
<Suspense fallback={<p className="koenig-react-editor-loading">Loading editor...</p>}>
|
||||
<KoenigComposer
|
||||
editorResource={this.editorResource}
|
||||
cardConfig={cardConfig}
|
||||
enableMultiplayer={enableMultiplayer}
|
||||
fileUploader={{useFileUpload, fileTypes}}
|
||||
initialEditorState={this.args.lexical}
|
||||
multiplayerUsername={multiplayerUsername}
|
||||
multiplayerDocId={multiplayerDocId}
|
||||
multiplayerEndpoint={multiplayerEndpoint}
|
||||
onError={this.onError}
|
||||
darkMode={this.feature.nightShift}
|
||||
isTKEnabled={true}
|
||||
>
|
||||
<KoenigEditor
|
||||
editorResource={this.editorResource}
|
||||
cursorDidExitAtTop={this.args.cursorDidExitAtTop}
|
||||
placeholderText={this.args.placeholder}
|
||||
darkMode={this.feature.nightShift}
|
||||
onChange={this.args.onChange}
|
||||
registerAPI={this.args.registerAPI}
|
||||
/>
|
||||
<WordCountPlugin editorResource={this.editorResource} onChange={this.args.updateWordCount} />
|
||||
<TKCountPlugin editorResource={this.editorResource} onChange={this.args.updatePostTkCount} />
|
||||
</KoenigComposer>
|
||||
<KGEditorComponent />
|
||||
<KGEditorComponent isInitInstance={true} />
|
||||
</Suspense>
|
||||
</ErrorHandler>
|
||||
</div>
|
||||
|
@ -33,6 +33,7 @@
|
||||
@lexical={{this.selectedRevision.lexical}}
|
||||
@cardConfig={{this.cardConfig}}
|
||||
@registerAPI={{this.registerSelectedEditorApi}}
|
||||
@registerSecondaryAPI={{this.registerSecondarySelectedEditorApi}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,6 +31,7 @@ export default class ModalPostHistory extends Component {
|
||||
super(...arguments);
|
||||
this.post = this.args.model.post;
|
||||
this.editorAPI = this.args.model.editorAPI;
|
||||
this.secondaryEditorAPI = this.args.model.secondaryEditorAPI;
|
||||
this.toggleSettingsMenu = this.args.model.toggleSettingsMenu;
|
||||
}
|
||||
|
||||
@ -101,6 +102,11 @@ export default class ModalPostHistory extends Component {
|
||||
this.selectedEditor = api;
|
||||
}
|
||||
|
||||
@action
|
||||
registerSecondarySelectedEditorApi(api) {
|
||||
this.secondarySelectedEditor = api;
|
||||
}
|
||||
|
||||
@action
|
||||
registerComparisonEditorApi(api) {
|
||||
this.comparisonEditor = api;
|
||||
@ -130,6 +136,7 @@ export default class ModalPostHistory extends Component {
|
||||
updateEditor: () => {
|
||||
const state = this.editorAPI.editorInstance.parseEditorState(revision.lexical);
|
||||
this.editorAPI.editorInstance.setEditorState(state);
|
||||
this.secondaryEditorAPI.editorInstance.setEditorState(state);
|
||||
},
|
||||
closePostHistoryModal: () => {
|
||||
this.closeModal();
|
||||
|
@ -297,6 +297,11 @@ export default class LexicalEditorController extends Controller {
|
||||
this._timedSaveTask.perform();
|
||||
}
|
||||
|
||||
@action
|
||||
updateSecondaryInstanceModel(lexical) {
|
||||
this.set('post.secondaryLexicalState', JSON.stringify(lexical));
|
||||
}
|
||||
|
||||
@action
|
||||
updateTitleScratch(title) {
|
||||
this.set('post.titleScratch', title);
|
||||
@ -423,6 +428,11 @@ export default class LexicalEditorController extends Controller {
|
||||
this.editorAPI = API;
|
||||
}
|
||||
|
||||
@action
|
||||
registerSecondaryEditorAPI(API) {
|
||||
this.secondaryEditorAPI = API;
|
||||
}
|
||||
|
||||
@action
|
||||
clearFeatureImage() {
|
||||
this.post.set('featureImage', null);
|
||||
@ -1221,7 +1231,6 @@ export default class LexicalEditorController extends Controller {
|
||||
_timedSaveTask;
|
||||
|
||||
/* Private methods -------------------------------------------------------*/
|
||||
|
||||
_hasDirtyAttributes() {
|
||||
let post = this.post;
|
||||
|
||||
@ -1229,8 +1238,7 @@ export default class LexicalEditorController extends Controller {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the Adapter failed to save the post isError will be true
|
||||
// and we should consider the post still dirty.
|
||||
// If the Adapter failed to save the post, isError will be true, and we should consider the post still dirty.
|
||||
if (post.get('isError')) {
|
||||
this._leaveModalReason = {reason: 'isError', context: post.errors.messages};
|
||||
return true;
|
||||
@ -1245,37 +1253,32 @@ export default class LexicalEditorController extends Controller {
|
||||
return true;
|
||||
}
|
||||
|
||||
// titleScratch isn't an attr so needs a manual dirty check
|
||||
// Title scratch comparison
|
||||
if (post.titleScratch !== post.title) {
|
||||
this._leaveModalReason = {reason: 'title is different', context: {current: post.title, scratch: post.titleScratch}};
|
||||
return true;
|
||||
}
|
||||
|
||||
// scratch isn't an attr so needs a manual dirty check
|
||||
// Lexical and scratch comparison
|
||||
let lexical = post.get('lexical');
|
||||
let scratch = post.get('lexicalScratch');
|
||||
// additional guard in case we are trying to compare null with undefined
|
||||
if (scratch || lexical) {
|
||||
if (scratch !== lexical) {
|
||||
// lexical can dynamically set direction on loading editor state (e.g. "rtl"/"ltr") per the DOM context
|
||||
// and we need to ignore this as a change from the user; see https://github.com/facebook/lexical/issues/4998
|
||||
const scratchChildNodes = scratch ? JSON.parse(scratch).root?.children : [];
|
||||
const lexicalChildNodes = lexical ? JSON.parse(lexical).root?.children : [];
|
||||
let secondaryLexical = post.get('secondaryLexicalState');
|
||||
|
||||
// // nullling is typically faster than delete
|
||||
scratchChildNodes.forEach(child => child.direction = null);
|
||||
lexicalChildNodes.forEach(child => child.direction = null);
|
||||
let lexicalChildNodes = lexical ? JSON.parse(lexical).root?.children : [];
|
||||
let scratchChildNodes = scratch ? JSON.parse(scratch).root?.children : [];
|
||||
let secondaryLexicalChildNodes = secondaryLexical ? JSON.parse(secondaryLexical).root?.children : [];
|
||||
|
||||
if (JSON.stringify(scratchChildNodes) === JSON.stringify(lexicalChildNodes)) {
|
||||
return false;
|
||||
}
|
||||
lexicalChildNodes.forEach(child => child.direction = null);
|
||||
scratchChildNodes.forEach(child => child.direction = null);
|
||||
secondaryLexicalChildNodes.forEach(child => child.direction = null);
|
||||
|
||||
this._leaveModalReason = {reason: 'lexical is different', context: {current: lexical, scratch}};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Compare initLexical with scratch
|
||||
let isSecondaryDirty = secondaryLexical && scratch && JSON.stringify(secondaryLexicalChildNodes) !== JSON.stringify(scratchChildNodes);
|
||||
|
||||
// new+unsaved posts always return `hasDirtyAttributes: true`
|
||||
// Compare lexical with scratch
|
||||
let isLexicalDirty = lexical && scratch && JSON.stringify(lexicalChildNodes) !== JSON.stringify(scratchChildNodes);
|
||||
|
||||
// New+unsaved posts always return `hasDirtyAttributes: true`
|
||||
// so we need a manual check to see if any
|
||||
if (post.get('isNew')) {
|
||||
let changedAttributes = Object.keys(post.changedAttributes());
|
||||
@ -1286,15 +1289,26 @@ export default class LexicalEditorController extends Controller {
|
||||
return changedAttributes.length ? true : false;
|
||||
}
|
||||
|
||||
// we've covered all the non-tracked cases we care about so fall
|
||||
// We've covered all the non-tracked cases we care about so fall
|
||||
// back on Ember Data's default dirty attribute checks
|
||||
let {hasDirtyAttributes} = post;
|
||||
|
||||
if (hasDirtyAttributes) {
|
||||
this._leaveModalReason = {reason: 'post.hasDirtyAttributes === true', context: post.changedAttributes()};
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasDirtyAttributes;
|
||||
// If either comparison is not dirty, return false, because scratch is always up to date.
|
||||
if (!isSecondaryDirty || !isLexicalDirty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If both comparisons are dirty, consider the post dirty
|
||||
if (isSecondaryDirty && isLexicalDirty) {
|
||||
this._leaveModalReason = {reason: 'initLexical and lexical are different from scratch', context: {secondaryLexical, lexical, scratch}};
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_showSaveNotification(prevStatus, status, delayed) {
|
||||
|
@ -136,6 +136,9 @@ export default Model.extend(Comparable, ValidationEngine, {
|
||||
scratch: null,
|
||||
lexicalScratch: null,
|
||||
titleScratch: null,
|
||||
//This is used to store the initial lexical state from the
|
||||
// secondary editor to get the schema up to date in case its outdated
|
||||
secondaryLexicalState: null,
|
||||
|
||||
// For use by date/time pickers - will be validated then converted to UTC
|
||||
// on save. Updated by an observer whenever publishedAtUTC changes.
|
||||
|
@ -73,6 +73,7 @@
|
||||
@body={{readonly this.post.lexicalScratch}}
|
||||
@bodyPlaceholder={{concat "Begin writing your " this.post.displayName "..."}}
|
||||
@onBodyChange={{this.updateScratch}}
|
||||
@updateSecondaryInstanceModel={{this.updateSecondaryInstanceModel}}
|
||||
@headerOffset={{editor.headerHeight}}
|
||||
@scrollContainerSelector=".gh-koenig-editor"
|
||||
@scrollOffsetBottomSelector=".gh-mobile-nav-bar"
|
||||
@ -97,6 +98,7 @@
|
||||
}}
|
||||
@postType={{this.post.displayName}}
|
||||
@registerAPI={{this.registerEditorAPI}}
|
||||
@registerSecondaryAPI={{this.registerSecondaryEditorAPI}}
|
||||
@savePostTask={{this.savePostTask}}
|
||||
/>
|
||||
|
||||
@ -136,6 +138,7 @@
|
||||
@updateSlugTask={{this.updateSlugTask}}
|
||||
@savePostTask={{this.savePostTask}}
|
||||
@editorAPI={{this.editorAPI}}
|
||||
@secondaryEditorAPI={{this.secondaryEditorAPI}}
|
||||
@toggleSettingsMenu={{this.toggleSettingsMenu}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
@ -208,7 +208,8 @@ describe('Unit: Controller: lexical-editor', function () {
|
||||
titleScratch: 'this is a title',
|
||||
status: 'published',
|
||||
lexical: initialLexicalString,
|
||||
lexicalScratch: initialLexicalString
|
||||
lexicalScratch: initialLexicalString,
|
||||
secondaryLexicalState: initialLexicalString
|
||||
}));
|
||||
|
||||
// synthetically update the lexicalScratch as if the editor itself made the modifications on loading the initial editorState
|
||||
@ -225,5 +226,47 @@ describe('Unit: Controller: lexical-editor', function () {
|
||||
isDirty = controller.get('hasDirtyAttributes');
|
||||
expect(isDirty).to.be.true;
|
||||
});
|
||||
|
||||
it('dirty is false if secondaryLexical and scratch matches, but lexical is outdated', async function () {
|
||||
const initialLexicalString = `{"root":{"children":[{"children": [{"detail": 0,"format": 0,"mode": "normal","style": "","text": "Sample content","type": "extended-text","version": 1}],"direction": null,"format": "","indent": 0,"type": "paragraph","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "root","version": 1}}`;
|
||||
const lexicalScratch = `{"root":{"children":[{"children": [{"detail": 0,"format": 0,"mode": "normal","style": "","text": "Sample content","type": "extended-text","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "paragraph","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "root","version": 1}}`;
|
||||
const secondLexicalInstance = `{"root":{"children":[{"children": [{"detail": 0,"format": 0,"mode": "normal","style": "","text": "Here's some new text","type": "extended-text","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "paragraph","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "root","version": 1}}`;
|
||||
|
||||
let controller = this.owner.lookup('controller:lexical-editor');
|
||||
controller.set('post', EmberObject.create({
|
||||
title: 'this is a title',
|
||||
titleScratch: 'this is a title',
|
||||
status: 'published',
|
||||
lexical: initialLexicalString,
|
||||
lexicalScratch: lexicalScratch,
|
||||
secondaryLexicalState: secondLexicalInstance
|
||||
}));
|
||||
|
||||
let isDirty = controller.get('hasDirtyAttributes');
|
||||
|
||||
expect(isDirty).to.be.false;
|
||||
});
|
||||
|
||||
it('dirty is true if secondaryLexical and lexical does not match scratch', async function () {
|
||||
const initialLexicalString = `{"root":{"children":[{"children": [{"detail": 0,"format": 0,"mode": "normal","style": "","text": "Sample content","type": "extended-text","version": 1}],"direction": null,"format": "","indent": 0,"type": "paragraph","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "root","version": 1}}`;
|
||||
const lexicalScratch = `{"root":{"children":[{"children": [{"detail": 0,"format": 0,"mode": "normal","style": "","text": "Sample content1234","type": "extended-text","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "paragraph","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "root","version": 1}}`;
|
||||
const secondLexicalInstance = `{"root":{"children":[{"children": [{"detail": 0,"format": 0,"mode": "normal","style": "","text": "Here's some new text","type": "extended-text","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "paragraph","version": 1}],"direction": "ltr","format": "","indent": 0,"type": "root","version": 1}}`;
|
||||
|
||||
let controller = this.owner.lookup('controller:lexical-editor');
|
||||
controller.set('post', EmberObject.create({
|
||||
title: 'this is a title',
|
||||
titleScratch: 'this is a title',
|
||||
status: 'published',
|
||||
lexical: initialLexicalString,
|
||||
lexicalScratch: lexicalScratch,
|
||||
secondaryLexicalState: secondLexicalInstance
|
||||
}));
|
||||
|
||||
controller.send('updateScratch',JSON.parse(lexicalScratch));
|
||||
|
||||
let isDirty = controller.get('hasDirtyAttributes');
|
||||
|
||||
expect(isDirty).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -24,11 +24,11 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/promise": "0.3.10",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/validator": "0.2.11",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/promise": "0.3.12",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"@tryghost/validator": "0.2.14",
|
||||
"jsonpath": "1.1.1",
|
||||
"lodash": "4.17.21"
|
||||
}
|
||||
|
@ -24,8 +24,8 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"bson-objectid": "2.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,6 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/logging": "2.4.15"
|
||||
"@tryghost/logging": "2.4.18"
|
||||
}
|
||||
}
|
||||
|
@ -26,14 +26,14 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/in-memory-repository": "0.0.0",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/nql": "0.12.3",
|
||||
"@tryghost/nql-filter-expansions": "0.0.0",
|
||||
"@tryghost/post-events": "0.0.0",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"bson-objectid": "2.0.4",
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
|
@ -17,6 +17,7 @@ class StaffServiceWrapper {
|
||||
const mailer = new GhostMailer();
|
||||
const settingsCache = require('../../../shared/settings-cache');
|
||||
const urlUtils = require('../../../shared/url-utils');
|
||||
const {blogIcon} = require('../../../server/lib/image');
|
||||
const settingsHelpers = require('../settings-helpers');
|
||||
|
||||
this.api = new StaffService({
|
||||
@ -26,6 +27,7 @@ class StaffServiceWrapper {
|
||||
settingsHelpers,
|
||||
settingsCache,
|
||||
urlUtils,
|
||||
blogIcon,
|
||||
DomainEvents,
|
||||
memberAttributionService: memberAttribution.service,
|
||||
labs
|
||||
|
@ -76,7 +76,7 @@
|
||||
"@tryghost/api-framework": "0.0.0",
|
||||
"@tryghost/api-version-compatibility-service": "0.0.0",
|
||||
"@tryghost/audience-feedback": "0.0.0",
|
||||
"@tryghost/bookshelf-plugins": "0.6.19",
|
||||
"@tryghost/bookshelf-plugins": "0.6.21",
|
||||
"@tryghost/bootstrap-socket": "0.0.0",
|
||||
"@tryghost/collections": "0.0.0",
|
||||
"@tryghost/color-utils": "0.2.2",
|
||||
@ -84,24 +84,24 @@
|
||||
"@tryghost/constants": "0.0.0",
|
||||
"@tryghost/custom-theme-settings-service": "0.0.0",
|
||||
"@tryghost/data-generator": "0.0.0",
|
||||
"@tryghost/database-info": "0.3.24",
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/database-info": "0.3.27",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/donations": "0.0.0",
|
||||
"@tryghost/dynamic-routing-events": "0.0.0",
|
||||
"@tryghost/email-analytics-provider-mailgun": "0.0.0",
|
||||
"@tryghost/email-analytics-service": "0.0.0",
|
||||
"@tryghost/email-content-generator": "0.0.0",
|
||||
"@tryghost/email-mock-receiver": "0.3.6",
|
||||
"@tryghost/email-mock-receiver": "0.3.8",
|
||||
"@tryghost/email-service": "0.0.0",
|
||||
"@tryghost/email-suppression-list": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/express-dynamic-redirects": "0.0.0",
|
||||
"@tryghost/external-media-inliner": "0.0.0",
|
||||
"@tryghost/ghost": "0.0.0",
|
||||
"@tryghost/helpers": "1.1.90",
|
||||
"@tryghost/html-to-plaintext": "0.0.0",
|
||||
"@tryghost/http-cache-utils": "0.1.15",
|
||||
"@tryghost/http-cache-utils": "0.1.17",
|
||||
"@tryghost/i18n": "0.0.0",
|
||||
"@tryghost/image-transform": "1.3.0",
|
||||
"@tryghost/importer-handler-content-files": "0.0.0",
|
||||
@ -119,7 +119,7 @@
|
||||
"@tryghost/link-redirects": "0.0.0",
|
||||
"@tryghost/link-replacer": "0.0.0",
|
||||
"@tryghost/link-tracking": "0.0.0",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/magic-link": "0.0.0",
|
||||
"@tryghost/mail-events": "0.0.0",
|
||||
"@tryghost/mailgun-client": "0.0.0",
|
||||
@ -143,16 +143,16 @@
|
||||
"@tryghost/mw-session-from-token": "0.0.0",
|
||||
"@tryghost/mw-version-match": "0.0.0",
|
||||
"@tryghost/mw-vhost": "0.0.0",
|
||||
"@tryghost/nodemailer": "0.3.42",
|
||||
"@tryghost/nodemailer": "0.3.45",
|
||||
"@tryghost/nql": "0.12.3",
|
||||
"@tryghost/oembed-service": "0.0.0",
|
||||
"@tryghost/package-json": "0.0.0",
|
||||
"@tryghost/post-revisions": "0.0.0",
|
||||
"@tryghost/posts-service": "0.0.0",
|
||||
"@tryghost/pretty-cli": "1.2.42",
|
||||
"@tryghost/promise": "0.3.10",
|
||||
"@tryghost/pretty-cli": "1.2.44",
|
||||
"@tryghost/promise": "0.3.12",
|
||||
"@tryghost/recommendations": "0.0.0",
|
||||
"@tryghost/request": "1.0.5",
|
||||
"@tryghost/request": "1.0.8",
|
||||
"@tryghost/security": "0.0.0",
|
||||
"@tryghost/session-service": "0.0.0",
|
||||
"@tryghost/settings-path-manager": "0.0.0",
|
||||
@ -162,14 +162,14 @@
|
||||
"@tryghost/stats-service": "0.0.0",
|
||||
"@tryghost/string": "0.2.12",
|
||||
"@tryghost/tiers": "0.0.0",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"@tryghost/update-check-service": "0.0.0",
|
||||
"@tryghost/url-utils": "4.4.8",
|
||||
"@tryghost/validator": "0.2.11",
|
||||
"@tryghost/validator": "0.2.14",
|
||||
"@tryghost/verification-trigger": "0.0.0",
|
||||
"@tryghost/version": "0.1.28",
|
||||
"@tryghost/version": "0.1.30",
|
||||
"@tryghost/webmentions": "0.0.0",
|
||||
"@tryghost/zip": "1.1.43",
|
||||
"@tryghost/zip": "1.1.46",
|
||||
"amperize": "0.6.1",
|
||||
"body-parser": "1.20.2",
|
||||
"bookshelf": "1.2.0",
|
||||
@ -210,7 +210,7 @@
|
||||
"knex-migrator": "5.2.1",
|
||||
"lib0": "0.2.94",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.4.4",
|
||||
"luxon": "3.5.0",
|
||||
"moment": "2.24.0",
|
||||
"moment-timezone": "0.5.45",
|
||||
"multer": "1.4.4",
|
||||
@ -237,8 +237,8 @@
|
||||
"devDependencies": {
|
||||
"@actions/core": "1.10.1",
|
||||
"@playwright/test": "1.38.1",
|
||||
"@tryghost/express-test": "0.13.12",
|
||||
"@tryghost/webhook-mock-receiver": "0.2.12",
|
||||
"@tryghost/express-test": "0.13.15",
|
||||
"@tryghost/webhook-mock-receiver": "0.2.14",
|
||||
"@types/common-tags": "1.8.4",
|
||||
"c8": "8.0.1",
|
||||
"cli-progress": "3.12.0",
|
||||
@ -265,8 +265,8 @@
|
||||
"toml": "3.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"jackspeak": "2.1.1",
|
||||
"moment": "2.24.0",
|
||||
"moment-timezone": "0.5.45"
|
||||
|
@ -78,7 +78,7 @@ const createPage = async (page, {title = 'Hello world', body = 'This is my post
|
||||
await page.locator('[data-test-editor-title-input]').fill(title);
|
||||
|
||||
// wait for editor to be ready
|
||||
await expect(page.locator('[data-lexical-editor="true"]')).toBeVisible();
|
||||
await expect(page.locator('[data-lexical-editor="true"]').first()).toBeVisible();
|
||||
|
||||
// Continue to the body by pressing enter
|
||||
await page.keyboard.press('Enter');
|
||||
@ -304,7 +304,7 @@ test.describe('Publishing', () => {
|
||||
await expect(publishedHeader).toContainText(date.toFormat('LLL d, yyyy'));
|
||||
|
||||
// add some extra text to the post
|
||||
await adminPage.locator('[data-kg="editor"]').click();
|
||||
await adminPage.locator('[data-kg="editor"]').first().click();
|
||||
await adminPage.waitForTimeout(200); //
|
||||
await adminPage.keyboard.type(' This is some updated text.');
|
||||
|
||||
|
@ -423,7 +423,7 @@ const createPostDraft = async (page, {title = 'Hello world', body = 'This is my
|
||||
await page.locator('[data-test-editor-title-input]').fill(title);
|
||||
|
||||
// wait for editor to be ready
|
||||
await expect(page.locator('[data-lexical-editor="true"]')).toBeVisible();
|
||||
await expect(page.locator('[data-lexical-editor="true"]').first()).toBeVisible();
|
||||
|
||||
// Continue to the body by pressing enter
|
||||
await page.keyboard.press('Enter');
|
||||
|
@ -25,10 +25,10 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/nql": "0.12.3",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"lodash": "4.17.21"
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
"lib"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"c8": "8.0.1",
|
||||
"knex": "2.4.2",
|
||||
"mocha": "10.2.0",
|
||||
@ -27,7 +27,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "7.6.0",
|
||||
"@tryghost/root-utils": "0.3.28",
|
||||
"@tryghost/root-utils": "0.3.30",
|
||||
"@tryghost/string": "0.2.12",
|
||||
"csv-writer": "1.6.0",
|
||||
"probability-distributions": "0.9.1"
|
||||
|
@ -19,7 +19,7 @@
|
||||
"lib"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"c8": "8.0.1",
|
||||
"mocha": "10.2.0",
|
||||
"should": "13.2.3"
|
||||
|
@ -23,7 +23,7 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"lodash": "4.17.21"
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,12 @@
|
||||
"dependencies": {
|
||||
"@tryghost/color-utils": "0.2.2",
|
||||
"@tryghost/email-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/html-to-plaintext": "0.0.0",
|
||||
"@tryghost/kg-default-cards": "10.0.6",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/validator": "0.2.11",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"@tryghost/validator": "0.2.14",
|
||||
"bson-objectid": "2.0.4",
|
||||
"cheerio": "0.22.0",
|
||||
"handlebars": "4.7.8",
|
||||
|
@ -36,7 +36,7 @@
|
||||
"@nestjs/common": "10.3.10",
|
||||
"@nestjs/core": "10.3.10",
|
||||
"@nestjs/platform-express": "10.3.10",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"bson-objectid": "2.0.4",
|
||||
"express": "4.19.2",
|
||||
"reflect-metadata": "0.1.14",
|
||||
|
@ -21,7 +21,7 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/kg-default-cards": "10.0.6",
|
||||
"@tryghost/string": "0.2.12",
|
||||
"lodash": "4.17.21",
|
||||
|
@ -28,8 +28,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@breejs/later": "4.2.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"bree": "6.5.0",
|
||||
"cron-validate": "1.4.5",
|
||||
"fastq": "1.17.1",
|
||||
|
@ -24,10 +24,10 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/link-redirects": "0.0.0",
|
||||
"@tryghost/nql": "0.12.3",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"bson-objectid": "2.0.4",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4"
|
||||
|
@ -26,9 +26,9 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/validator": "0.2.11",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"@tryghost/validator": "0.2.14",
|
||||
"jsonwebtoken": "8.5.1"
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,9 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/in-memory-repository": "0.0.0",
|
||||
"@tryghost/tpl": "0.1.30"
|
||||
"@tryghost/tpl": "0.1.32"
|
||||
},
|
||||
"c8": {
|
||||
"exclude": [
|
||||
|
@ -24,8 +24,8 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/metrics": "1.0.34",
|
||||
"form-data": "4.0.0",
|
||||
"lodash": "4.17.21",
|
||||
|
@ -31,14 +31,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/magic-link": "0.0.0",
|
||||
"@tryghost/member-events": "0.0.0",
|
||||
"@tryghost/members-payments": "0.0.0",
|
||||
"@tryghost/nql": "0.12.3",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/validator": "0.2.11",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"@tryghost/validator": "0.2.14",
|
||||
"@types/jsonwebtoken": "9.0.6",
|
||||
"body-parser": "1.20.2",
|
||||
"bson-objectid": "2.0.4",
|
||||
|
@ -26,8 +26,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/member-events": "0.0.0",
|
||||
"moment-timezone": "0.5.34"
|
||||
}
|
||||
|
@ -25,11 +25,11 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/members-csv": "0.0.0",
|
||||
"@tryghost/metrics": "1.0.34",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"moment-timezone": "0.5.45"
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,8 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"cookies": "0.9.1",
|
||||
"jsonwebtoken": "8.5.1"
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"bson-objectid": "2.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,9 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"csso": "5.0.5",
|
||||
"terser": "5.31.3",
|
||||
"tiny-glob": "0.2.9"
|
||||
|
@ -18,7 +18,7 @@
|
||||
"lib"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"c8": "8.0.1",
|
||||
"mocha": "10.2.0",
|
||||
"sinon": "15.2.0"
|
||||
|
@ -23,10 +23,10 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/http-cache-utils": "0.1.15",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/http-cache-utils": "0.1.17",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"lodash": "4.17.21",
|
||||
"semver": "7.6.3"
|
||||
}
|
||||
|
@ -23,8 +23,8 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"semver": "7.6.3"
|
||||
}
|
||||
}
|
||||
|
@ -23,9 +23,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@extractus/oembed-extractor": "3.2.1",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"charset": "1.0.1",
|
||||
"cheerio": "0.22.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
|
@ -26,7 +26,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/mongo-utils": "0.6.2",
|
||||
"@tryghost/string": "0.2.12",
|
||||
"lodash": "4.17.21"
|
||||
|
@ -25,8 +25,8 @@
|
||||
"tmp": "0.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"fs-extra": "11.2.0",
|
||||
"lodash": "4.17.21"
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/members-offers": "0.0.0",
|
||||
"@tryghost/tiers": "0.0.0"
|
||||
}
|
||||
|
@ -23,10 +23,10 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/nql": "0.12.3",
|
||||
"@tryghost/post-events": "0.0.0",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"bson-objectid": "2.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -30,10 +30,10 @@
|
||||
"typescript": "5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/in-memory-repository": "0.0.0",
|
||||
"@tryghost/bookshelf-repository": "0.0.0",
|
||||
"@tryghost/logging": "2.4.15"
|
||||
"@tryghost/logging": "2.4.18"
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,6 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2"
|
||||
"@tryghost/errors": "1.3.5"
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,8 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"date-fns": "2.30.0"
|
||||
}
|
||||
}
|
||||
|
@ -23,9 +23,9 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/validator": "0.2.11",
|
||||
"@tryghost/version": "0.1.28",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/validator": "0.2.14",
|
||||
"@tryghost/version": "0.1.30",
|
||||
"got": "9.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ const {MilestoneCreatedEvent} = require('@tryghost/milestones');
|
||||
// @NOTE: 'StaffService' is a vague name that does not describe what it's actually doing.
|
||||
// Possibly, "StaffNotificationService" or "StaffEventNotificationService" would be a more accurate name
|
||||
class StaffService {
|
||||
constructor({logging, models, mailer, settingsCache, settingsHelpers, urlUtils, DomainEvents, labs, memberAttributionService}) {
|
||||
constructor({logging, models, mailer, settingsCache, settingsHelpers, urlUtils, blogIcon, DomainEvents, labs, memberAttributionService}) {
|
||||
this.logging = logging;
|
||||
this.labs = labs;
|
||||
/** @private */
|
||||
@ -22,6 +22,7 @@ class StaffService {
|
||||
settingsHelpers,
|
||||
settingsCache,
|
||||
urlUtils,
|
||||
blogIcon,
|
||||
labs
|
||||
});
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ const glob = require('glob');
|
||||
const {EmailAddressParser} = require('@tryghost/email-addresses');
|
||||
|
||||
class StaffServiceEmails {
|
||||
constructor({logging, models, mailer, settingsHelpers, settingsCache, urlUtils, labs}) {
|
||||
constructor({logging, models, mailer, settingsHelpers, settingsCache, blogIcon, urlUtils, labs}) {
|
||||
this.logging = logging;
|
||||
this.models = models;
|
||||
this.mailer = mailer;
|
||||
this.settingsHelpers = settingsHelpers;
|
||||
this.settingsCache = settingsCache;
|
||||
this.blogIcon = blogIcon;
|
||||
this.urlUtils = urlUtils;
|
||||
this.labs = labs;
|
||||
|
||||
@ -44,6 +45,7 @@ class StaffServiceEmails {
|
||||
attributionUrl: attribution?.url || '',
|
||||
referrerSource: attribution?.referrerSource,
|
||||
siteTitle: this.settingsCache.get('title'),
|
||||
siteIconUrl: this.blogIcon.getIconUrl(true),
|
||||
siteUrl: this.urlUtils.getSiteUrl(),
|
||||
siteDomain: this.siteDomain,
|
||||
accentColor: this.settingsCache.get('accent_color'),
|
||||
@ -103,6 +105,7 @@ class StaffServiceEmails {
|
||||
offerData,
|
||||
subscriptionData,
|
||||
siteTitle: this.settingsCache.get('title'),
|
||||
siteIconUrl: this.blogIcon.getIconUrl(true),
|
||||
siteUrl: this.urlUtils.getSiteUrl(),
|
||||
siteDomain: this.siteDomain,
|
||||
accentColor: this.settingsCache.get('accent_color'),
|
||||
@ -153,6 +156,7 @@ class StaffServiceEmails {
|
||||
tierData,
|
||||
subscriptionData,
|
||||
siteTitle: this.settingsCache.get('title'),
|
||||
siteIconUrl: this.blogIcon.getIconUrl(true),
|
||||
siteUrl: this.urlUtils.getSiteUrl(),
|
||||
siteDomain: this.siteDomain,
|
||||
accentColor: this.settingsCache.get('accent_color'),
|
||||
@ -182,6 +186,7 @@ class StaffServiceEmails {
|
||||
|
||||
return {
|
||||
siteTitle: this.settingsCache.get('title'),
|
||||
siteIconUrl: this.blogIcon.getIconUrl(true),
|
||||
siteUrl: this.urlUtils.getSiteUrl(),
|
||||
siteDomain: this.siteDomain,
|
||||
accentColor: this.settingsCache.get('accent_color'),
|
||||
@ -282,6 +287,7 @@ class StaffServiceEmails {
|
||||
const templateData = {
|
||||
siteTitle: this.settingsCache.get('title'),
|
||||
siteUrl: this.urlUtils.getSiteUrl(),
|
||||
siteIconUrl: this.blogIcon.getIconUrl(true),
|
||||
siteDomain: this.siteDomain,
|
||||
fromEmail: this.fromEmailAddress,
|
||||
toEmail: to,
|
||||
|
@ -21,21 +21,33 @@
|
||||
<tr>
|
||||
<td class="wrapper" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; box-sizing: border-box;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
||||
{{#if siteIconUrl}}
|
||||
<tr>
|
||||
<td align="center" style="padding-bottom: 56px; text-align: center;"><a href="{{siteUrl}}"><img src="{{siteIconUrl}}" alt="{{siteTitle}}" border="0" width="48" height="48"></a></td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
|
||||
<h1 style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 26px; color: #15212A; font-weight: bold; line-height: 28px; margin: 0; margin-bottom: 15px;">Cha-ching! 💰 You received {{donation.amount}} from {{donation.name}}.</h1>
|
||||
<table width="100" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; table-layout: fixed; width: 100%; min-width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
|
||||
<h1 style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 26px; color: #15212A; font-weight: bold; line-height: 28px; margin: 0; padding-bottom: 24px;">Cha-ching! You received a {{donation.amount}} tip from {{donation.name}}.</h1>
|
||||
<table width="100" border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; table-layout: fixed; width: 100%; min-width: 100%; box-sizing: border-box; background: #F4F5F6; border-radius: 8px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="padding: 32px 24px; text-align: center;">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 400;">Type:</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 17px; line-height: 26px; padding: 0; text-align: left; margin: 0; margin-bottom: 20px; color: #15171A; font-weight: 700;">One-time payment</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 400;">From:</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 17px; line-height: 26px; padding: 0; text-align: left; margin: 0; margin-bottom: 20px; color: #15171A; font-weight: 700;">{{#if memberData}}<a style="color:{{accentColor}}" href="{{memberData.adminUrl}}">{{donation.name}} ({{donation.email}})</a>{{else}}{{donation.name}} ({{donation.email}}){{/if}}</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 400;">Amount received:</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 17px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 700;">{{donation.amount}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding: 24px; text-align: center;">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 400;">From:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; line-height: 26px; padding: 0; text-align: left; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 700;">{{donation.name}} (<span style="color:{{accentColor}}; text-decoration: none;">{{donation.email}}</span>)</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 400;">Amount received:</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; line-height: 26px; padding: 0; text-align: left; margin: 0; color: #15171A; font-weight: 700;">{{donation.amount}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:0 24px 24px;">
|
||||
{{#if memberData}}
|
||||
<a href="{{memberData.adminUrl}}" style="border:solid 1px {{accentColor}};border-radius:8px;box-sizing:border-box;display:inline-block;font-size:15px;font-weight:normal;margin:0;padding:10px 20px;text-decoration:none;background-color:{{accentColor}};border-color:{{accentColor}};color:#ffffff">View member</a>
|
||||
{{else}}
|
||||
<a href="{{adminUrl}}" style="border:solid 1px {{accentColor}};border-radius:8px;box-sizing:border-box;display:inline-block;font-size:15px;font-weight:normal;margin:0;padding:10px 20px;text-decoration:none;background-color:{{accentColor}};border-color:{{accentColor}};color:#ffffff">View dashboard</a>
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
@ -43,13 +55,13 @@
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 80px;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #738A94; font-weight: normal; margin: 0; margin-bottom: 2px;">This message was sent from <a class="small" href="{{siteUrl}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">{{siteDomain}}</a> to <a class="small" href="mailto:{{toEmail}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">{{toEmail}}</a></p>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; vertical-align: top; padding-top: 56px;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #7C8B9A; font-weight: normal; margin: 0;">This message was sent from <a class="small" href="{{siteUrl}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">{{siteDomain}}</a> to <a class="small" href="mailto:{{toEmail}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">{{toEmail}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 2px">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #738A94; font-weight: normal; margin: 0; margin-bottom: 2px;">Don’t want to receive these emails? Manage your preferences <a class="small" href="{{staffUrl}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">here</a>.</p>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; vertical-align: top;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #7C8B9A; font-weight: normal; margin: 0;">Don’t want to receive these emails? Manage your preferences <a class="small" href="{{staffUrl}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">here</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -26,64 +26,46 @@
|
||||
<tr>
|
||||
<td class="wrapper" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; box-sizing: border-box;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
||||
{{#if siteIconUrl}}
|
||||
<tr>
|
||||
<td align="center" style="padding-bottom: 56px; text-align: center;"><a href="{{siteUrl}}"><img src="{{siteIconUrl}}" alt="{{siteTitle}}" border="0" width="48" height="48"></a></td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 20px; color: #15212A; font-weight: bold; line-height: 25px; margin: 0; margin-bottom: 15px;">Congratulations!</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 32px;">You have a <span style="font-weight: bold; color: #15212A;">new free member</span>.</p>
|
||||
|
||||
<table width="100" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; table-layout: fixed; width: 100%; min-width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="padding: 16px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="padding-right: 14px; background-color: #F9F9FA; text-align: left; vertical-align: middle;" valign="middle">
|
||||
<div style="width: 48px; height: 48px; background-color: #15171A; border-radius: 999px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 19px; color: #FFFFFF; text-align: center; vertical-align: center; font-weight: 500; line-height: 47px;">
|
||||
{{memberData.initials}}
|
||||
</div>
|
||||
</td>
|
||||
<td style="padding-right: 8px; background-color: #F9F9FA; text-align: left; vertical-align: middle;" valign="middle">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600;">{{memberData.name}}</p>
|
||||
{{#if memberData.showEmail}}
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #394047; font-weight: 400;">{{memberData.email}}</p>
|
||||
{{/if}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #95A1AD;">Created on {{memberData.createdAt}}{{#if memberData.location}} • {{memberData.location}} {{/if}}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
|
||||
<tr>
|
||||
<td align="left" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; padding-top: 32px; padding-bottom: 12px;">
|
||||
{{#if referrerSource}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #95A1AD;">Signup info</p>
|
||||
<hr style="border-bottom: 1px solid #F4F4F5; margin-top: 4px; margin-bottom: 8px;" />
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600; padding-bottom: 4px;">Source
|
||||
<span style="font-weight: normal; color:#3A464C;"> - {{referrerSource}}</span>
|
||||
</p>
|
||||
{{#if attributionTitle}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600;">Page
|
||||
<span style="font-weight: normal; color:#3A464C;"> - <a href="{{attributionUrl}}" style="font-weight: normal; color:#3A464C;text-decoration:none">{{attributionTitle}}</a></span>
|
||||
</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
|
||||
<h1 style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 26px; color: #15212A; font-weight: bold; line-height: 28px; margin: 0; padding-bottom: 24px;">You have a new free member</h1>
|
||||
<table width="100" border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; table-layout: fixed; width: 100%; min-width: 100%; box-sizing: border-box; background: #F4F5F6; border-radius: 8px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; padding-top: 32px; padding-bottom: 12px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
|
||||
<td align="left" style="padding: 24px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="padding-right: 8px; background-color: #F4F5F6; text-align: left; vertical-align: middle;" valign="middle">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Name:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;">{{memberData.name}}{{#if memberData.showEmail}} ({{memberData.email}}){{/if}}</p>
|
||||
{{#if referrerSource}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Source:</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;">{{referrerSource}}</p>
|
||||
{{#if attributionTitle}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Page:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;"><a href="{{attributionUrl}}">{{attributionTitle}}</a></p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{memberData.adminUrl}}" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View member</a></td>
|
||||
<td align="left" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; vertical-align: top; background-color: {{accentColor}}; border-radius: 8px; text-align: center;"> <a href="{{memberData.adminUrl}}" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 8px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 15px; font-weight: normal; margin: 0; padding: 10px 20px; border-color: {{accentColor}};">View member</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -91,21 +73,29 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
|
||||
<p class="text-link" style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{memberData.adminUrl}}</p>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="padding-top: 24px;">
|
||||
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #7c8b9a; font-weight: normal; margin: 0; line-height: 25px;">Or copy and paste this URL into your browser:</p>
|
||||
<p class="text-link" style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin:0; color: #7c8b9a; font-weight: normal;">{{memberData.adminUrl}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 80px;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0; margin-bottom: 2px;">This message was sent from <a class="small" href="{{siteUrl}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">{{siteDomain}}</a> to <a class="small" href="mailto:{{toEmail}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">{{toEmail}}</a></p>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; vertical-align: top; padding-top: 56px;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #7C8B9A; font-weight: normal; margin: 0;">This message was sent from <a class="small" href="{{siteUrl}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">{{siteDomain}}</a> to <a class="small" href="mailto:{{toEmail}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">{{toEmail}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 2px">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0; margin-bottom: 2px;">Don’t want to receive these emails? Manage your preferences <a class="small" href="{{staffUrl}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">here</a>.</p>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; vertical-align: top;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #7C8B9A; font-weight: normal; margin: 0;">Don’t want to receive these emails? Manage your preferences <a class="small" href="{{staffUrl}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">here</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -26,77 +26,52 @@
|
||||
<tr>
|
||||
<td class="wrapper" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; box-sizing: border-box;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
||||
{{#if siteIconUrl}}
|
||||
<tr>
|
||||
<td align="center" style="padding-bottom: 56px; text-align: center;"><a href="{{siteUrl}}"><img src="{{siteIconUrl}}" alt="{{siteTitle}}" border="0" width="48" height="48"></a></td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 20px; color: #15212A; font-weight: bold; line-height: 25px; margin: 0; margin-bottom: 15px;">Congratulations!</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 32px;">You have a <span style="font-weight: bold; color: #15212A;">new paid member</span>.</p>
|
||||
|
||||
<table width="100" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; table-layout: fixed; width: 100%; min-width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="padding: 16px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="padding-right: 14px; vertical-align: middle;" valign="middle">
|
||||
<div style="width: 48px; height: 48px; background-color: #15171A; border-radius: 999px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 19px; color: #FFFFFF; text-align: center; vertical-align: center; font-weight: 500; line-height: 47px;">
|
||||
{{memberData.initials}}
|
||||
</div>
|
||||
</td>
|
||||
<td style="padding-right: 8px; vertical-align: middle;" valign="middle">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600;">{{memberData.name}}</p>
|
||||
{{#if memberData.showEmail}}
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #394047; font-weight: 400;">{{memberData.email}}</p>
|
||||
{{/if}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #95A1AD;">Subscription started on {{subscriptionData.startedOn}} </p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
|
||||
<tr>
|
||||
<td align="left" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; padding-top: 32px; padding-bottom: 12px;">
|
||||
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #95A1AD;">Tier</p>
|
||||
<hr style="border-bottom: 1px solid #F4F4F5; margin-top: 4px; margin-bottom: 8px;" />
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600; padding-bottom: 32px;">{{tierData.name}}
|
||||
{{#if tierData.details}} <span style="font-weight: normal; color:#3A464C;"> - {{tierData.details}}</span>{{/if}}
|
||||
</p>
|
||||
|
||||
{{#if offerData}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #95A1AD;">Offer</p>
|
||||
<hr style="border-bottom: 1px solid #F4F4F5; margin-top: 4px; margin-bottom: 8px;" />
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600; padding-bottom: 32px;">{{offerData.name}} <span style="font-weight: normal; color:#3A464C;"> - {{offerData.details}}</span></p>
|
||||
{{/if}}
|
||||
|
||||
{{#if referrerSource}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 13px; padding-right: 8px; padding: 0; margin: 0; color: #95A1AD;">Signup info</p>
|
||||
<hr style="border-bottom: 1px solid #F4F4F5; margin-top: 4px; margin-bottom: 8px;" />
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600; padding-bottom: 4px;">Source
|
||||
<span style="font-weight: normal; color:#3A464C;"> - {{referrerSource}}</span>
|
||||
</p>
|
||||
{{#if attributionTitle}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; padding-right: 8px; padding: 0; margin: 0; color: #15171A; font-weight: 600;">Page
|
||||
<span style="font-weight: normal; color:#3A464C;"> - <a href="{{attributionUrl}}" style="font-weight: normal; color:#3A464C;text-decoration:none">{{attributionTitle}}</a></span>
|
||||
</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
|
||||
<h1 style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 26px; color: #15212A; font-weight: bold; line-height: 28px; margin: 0; padding-bottom: 24px;">You have a new paid subscriber</h1>
|
||||
<table width="100" border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; table-layout: fixed; width: 100%; min-width: 100%; box-sizing: border-box; background: #F4F5F6; border-radius: 8px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; padding-top: 32px; padding-bottom: 12px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
|
||||
<td align="left" style="padding: 24px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="padding-right: 8px; background-color: #F4F5F6; text-align: left; vertical-align: middle;" valign="middle">
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Name:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;">{{memberData.name}}{{#if memberData.showEmail}} ({{memberData.email}}){{/if}}</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Tier:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;">{{tierData.name}}{{#if tierData.details}} • {{tierData.details}}{{/if}}</p>
|
||||
{{#if offerData}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Offer:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;">{{offerData.name}} • <span style="color: {{accentColor}};">{{offerData.details}}</span></p>
|
||||
{{/if}}
|
||||
{{#if referrerSource}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Source:</p>
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;">{{referrerSource}}</p>
|
||||
{{#if attributionTitle}}
|
||||
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; margin: 0; padding-bottom: 4px; color: #15171A; font-weight: 400;">Page:</p>
|
||||
<p class="text-link" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 18px; margin: 0; padding-bottom: 24px; color: #15171A; font-weight: 600;"><a href="{{attributionUrl}}">{{attributionTitle}}</a></p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: {{accentColor}}; border-radius: 5px; text-align: center;"> <a href="{{memberData.adminUrl}}" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: {{accentColor}};">View member</a> </td>
|
||||
<td align="left" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; vertical-align: top; background-color: {{accentColor}}; border-radius: 8px; text-align: center;"> <a href="{{memberData.adminUrl}}" target="_blank" style="display: inline-block; color: #ffffff; background-color: {{accentColor}}; border: solid 1px {{accentColor}}; border-radius: 8px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 15px; font-weight: normal; margin: 0; padding: 10px 20px; border-color: {{accentColor}};">View member</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -104,21 +79,29 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
|
||||
<p class="text-link" style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">{{memberData.adminUrl}}</p>
|
||||
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="padding-top: 24px;">
|
||||
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #7c8b9a; font-weight: normal; margin: 0; line-height: 25px;">Or copy and paste this URL into your browser:</p>
|
||||
<p class="text-link" style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin:0; color: #7c8b9a; font-weight: normal;">{{memberData.adminUrl}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 80px;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0; margin-bottom: 2px;">This message was sent from <a class="small" href="{{siteUrl}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">{{siteDomain}}</a> to <a class="small" href="mailto:{{toEmail}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">{{toEmail}}</a></p>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; vertical-align: top; padding-top: 56px;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #7C8B9A; font-weight: normal; margin: 0;">This message was sent from <a class="small" href="{{siteUrl}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">{{siteDomain}}</a> to <a class="small" href="mailto:{{toEmail}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">{{toEmail}}</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top; padding-top: 2px">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 11px; color: #738A94; font-weight: normal; margin: 0; margin-bottom: 2px;">Don’t want to receive these emails? Manage your preferences <a class="small" href="{{staffUrl}}" style="text-decoration: underline; color: #738A94; font-size: 11px;">here</a>.</p>
|
||||
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 12px; vertical-align: top;">
|
||||
<p class="small" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; line-height: 18px; font-size: 12px; color: #7C8B9A; font-weight: normal; margin: 0;">Don’t want to receive these emails? Manage your preferences <a class="small" href="{{staffUrl}}" style="text-decoration: underline; color: #7C8B9A; font-size: 12px;">here</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -78,10 +78,6 @@ function testCommonPaidSubMailData({member, mailStub, getEmailAlertUsersStub}) {
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('$50.00/month'))
|
||||
).should.be.true();
|
||||
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('Subscription started on 1 Aug 2022'))
|
||||
).should.be.true();
|
||||
}
|
||||
|
||||
function testCommonPaidSubCancelMailData({mailStub, getEmailAlertUsersStub}) {
|
||||
@ -149,6 +145,12 @@ describe('StaffService', function () {
|
||||
}
|
||||
};
|
||||
|
||||
const blogIcon = {
|
||||
getIconUrl: () => {
|
||||
return 'https://ghost.example/siteicon.png';
|
||||
}
|
||||
};
|
||||
|
||||
const settingsHelpers = {
|
||||
getDefaultEmailDomain: () => {
|
||||
return 'ghost.example';
|
||||
@ -184,6 +186,7 @@ describe('StaffService', function () {
|
||||
},
|
||||
settingsCache,
|
||||
urlUtils,
|
||||
blogIcon,
|
||||
settingsHelpers,
|
||||
labs
|
||||
});
|
||||
@ -220,6 +223,7 @@ describe('StaffService', function () {
|
||||
DomainEvents,
|
||||
settingsCache,
|
||||
urlUtils,
|
||||
blogIcon,
|
||||
settingsHelpers
|
||||
});
|
||||
service.subscribeEvents();
|
||||
@ -339,6 +343,7 @@ describe('StaffService', function () {
|
||||
},
|
||||
settingsCache,
|
||||
urlUtils,
|
||||
blogIcon,
|
||||
settingsHelpers,
|
||||
labs: {
|
||||
isSet: () => {
|
||||
@ -430,9 +435,6 @@ describe('StaffService', function () {
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('🥳 Free member signup: Ghost'))
|
||||
).should.be.true();
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('Created on 1 Aug 2022 • France'))
|
||||
).should.be.true();
|
||||
});
|
||||
|
||||
it('sends free member signup alert without member name', async function () {
|
||||
@ -455,18 +457,13 @@ describe('StaffService', function () {
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('🥳 Free member signup: member@example.com'))
|
||||
).should.be.true();
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('Created on 1 Aug 2022 • France'))
|
||||
).should.be.true();
|
||||
});
|
||||
|
||||
it('sends free member signup alert with attribution', async function () {
|
||||
const member = {
|
||||
name: 'Ghost',
|
||||
email: 'member@example.com',
|
||||
id: 'abc',
|
||||
geolocation: '{"country": "France"}',
|
||||
created_at: '2022-08-01T07:30:39.882Z'
|
||||
id: 'abc'
|
||||
};
|
||||
|
||||
const attribution = {
|
||||
@ -487,9 +484,6 @@ describe('StaffService', function () {
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('🥳 Free member signup: Ghost'))
|
||||
).should.be.true();
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('Created on 1 Aug 2022 • France'))
|
||||
).should.be.true();
|
||||
|
||||
mailStub.calledWith(
|
||||
sinon.match.has('html', sinon.match('Source'))
|
||||
@ -520,9 +514,7 @@ describe('StaffService', function () {
|
||||
member = {
|
||||
name: 'Ghost',
|
||||
email: 'member@example.com',
|
||||
id: 'abc',
|
||||
geolocation: '{"country": "France"}',
|
||||
created_at: '2022-08-01T07:30:39.882Z'
|
||||
id: 'abc'
|
||||
};
|
||||
offer = {
|
||||
name: 'Half price',
|
||||
@ -588,9 +580,7 @@ describe('StaffService', function () {
|
||||
it('sends paid subscription start alert without member name', async function () {
|
||||
let memberData = {
|
||||
email: 'member@example.com',
|
||||
id: 'abc',
|
||||
geolocation: '{"country": "France"}',
|
||||
created_at: '2022-08-01T07:30:39.882Z'
|
||||
id: 'abc'
|
||||
};
|
||||
await service.emails.notifyPaidSubscriptionStarted({member: memberData, offer: null, tier, subscription}, options);
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
"@types/sinon": "10.0.16",
|
||||
"c8": "8.0.1",
|
||||
"knex": "2.4.2",
|
||||
"luxon": "3.4.4",
|
||||
"luxon": "3.5.0",
|
||||
"mocha": "10.2.0",
|
||||
"should": "13.2.3",
|
||||
"sinon": "15.2.0",
|
||||
|
@ -25,10 +25,10 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/member-events": "0.0.0",
|
||||
"leaky-bucket": "2.2.0",
|
||||
"lodash": "4.17.21",
|
||||
|
@ -22,9 +22,9 @@
|
||||
"mocha": "10.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/string": "0.2.12",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"bson-objectid": "2.0.4"
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,10 @@
|
||||
"uuid": "9.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "0.1.30",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/tpl": "0.1.30",
|
||||
"@tryghost/debug": "0.1.32",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"@tryghost/tpl": "0.1.32",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.24.0"
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/member-events": "0.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@
|
||||
"sinon": "15.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"cheerio": "0.22.0"
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +43,8 @@
|
||||
"prepare": "husky install .github/hooks"
|
||||
},
|
||||
"resolutions": {
|
||||
"@tryghost/errors": "1.3.2",
|
||||
"@tryghost/logging": "2.4.15",
|
||||
"@tryghost/errors": "1.3.5",
|
||||
"@tryghost/logging": "2.4.18",
|
||||
"jackspeak": "2.1.1",
|
||||
"moment": "2.24.0",
|
||||
"moment-timezone": "0.5.45"
|
||||
@ -115,9 +115,9 @@
|
||||
"eslint-plugin-ghost": "3.4.0",
|
||||
"eslint-plugin-react": "7.33.0",
|
||||
"husky": "8.0.3",
|
||||
"lint-staged": "15.2.7",
|
||||
"lint-staged": "15.2.8",
|
||||
"nx": "16.8.1",
|
||||
"rimraf": "5.0.9",
|
||||
"rimraf": "5.0.10",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.4.5",
|
||||
"inquirer": "8.2.6"
|
||||
|
Loading…
Reference in New Issue
Block a user