Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,20 @@ services:
ports:
- "5433:5432"

redis:
image: redis:8.6-alpine
restart: always
ports:
- "6379:6379"
command: redis-server --save 60 1 --loglevel warning
volumes:
- cache:/data

networks:
elastic:

volumes:
jdma_kibana_data:
jdma_es_data:
jdma_es_certs:
cache:
257 changes: 257 additions & 0 deletions docs/alerts-architecture.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions webapp-backoffice/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@ PROCONNECT_CLIENT_SECRET=""
#INSEE
INSEE_API_URL="https://api.insee.fr"
INSEE_API_KEY=""

# Redis (BullMQ queue)
REDIS_URL=redis://localhost:6379

# Alert worker tuning
ALERT_WORKER_CONCURRENCY=5
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
Preview,
Section,
Text
} from '@react-email/components';
} from 'react-email';
import * as React from 'react';

interface JdmaLayoutProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,13 @@ export interface JdmaUserRequestRefusedEmailProps {
message?: string;
baseUrl?: string;
}

export interface JdmaAlertEmailProps {
userId?: number;
productTitle?: string;
formTitle?: string;
totalNbReviews?: number;
nbReviewsWithComments?: number;
reviewsUrl?: string;
baseUrl?: string;
}
105 changes: 105 additions & 0 deletions webapp-backoffice/emails/jdma-alert-email.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Button, Hr, Link, Section, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaAlertEmailProps } from './interface';

const formatNumber = (num: number) => {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
};

export const JdmaAlertEmail = ({
userId = 1,
productTitle = 'Service de démonstration',
formTitle = 'Formulaire de satisfaction',
totalNbReviews = 3,
nbReviewsWithComments = 2,
reviewsUrl = 'https://jedonnemonavis.numerique.gouv.fr/administration/dashboard/product/1/forms/1?tab=reviews',
baseUrl = 'https://jedonnemonavis.numerique.gouv.fr'
}: JdmaAlertEmailProps) => {
const reviewsLabel =
totalNbReviews === 1 ? 'nouvelle réponse' : 'nouvelles réponses';
const formattedTotal = formatNumber(totalNbReviews);

return (
<JdmaLayout
preview={`${formattedTotal} ${reviewsLabel} sur le formulaire ${formTitle}`}
baseUrl={baseUrl}
>
<Text style={paragraph}>Bonjour,</Text>

<Text style={paragraph}>
Vous avez reçu&nbsp;
<strong>
{formattedTotal} {reviewsLabel}
</strong>
{' nécessitant votre attention sur le formulaire '}
<strong>{formTitle}</strong>
{' du service '}
<strong>{productTitle}</strong>
{nbReviewsWithComments > 0
? `, dont ${formatNumber(nbReviewsWithComments)} avec ${
nbReviewsWithComments === 1 ? 'commentaire' : 'commentaires'
}.`
: '.'}
</Text>

<Section style={ctaSection}>
<Button href={reviewsUrl} style={ctaButton}>
Voir les nouvelles réponses
</Button>
</Section>

<Hr style={hr} />

<Text style={paragraph}>
Pour changer la fréquence de cette alerte ou ne plus la recevoir du
tout,&nbsp;
<Link
href={`${baseUrl}/administration/dashboard/user/${userId}/notifications`}
target="_blank"
style={linkStyle}
>
modifiez vos paramètres de notification
</Link>
.
</Text>
</JdmaLayout>
);
};

export default JdmaAlertEmail;

// Styles
const paragraph: React.CSSProperties = {
fontSize: '14px',
lineHeight: '1.5',
color: '#333333',
marginBottom: '16px'
};

const linkStyle: React.CSSProperties = {
color: '#000091',
textDecoration: 'underline'
};

const ctaSection: React.CSSProperties = {
textAlign: 'center' as const,
marginTop: '24px',
marginBottom: '24px'
};

const ctaButton: React.CSSProperties = {
backgroundColor: '#000091',
color: '#ffffff',
fontSize: '14px',
fontWeight: 'bold',
padding: '10px 20px',
textDecoration: 'none',
display: 'inline-block'
};

const hr: React.CSSProperties = {
borderColor: '#e0e0e0',
marginTop: '24px',
marginBottom: '24px'
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Column, Img, Link, Row, Section, Text } from '@react-email/components';
import { Column, Img, Link, Row, Section, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaClosedButtonOrFormEmailProps } from './interface';
Expand All @@ -24,7 +24,9 @@ export const JdmaClosedButtonOrFormEmail = ({

return (
<JdmaLayout
preview={`Fermeture ${buttonTitle ? "d'un lien d'intégration" : "d'un formulaire"} du service « ${product.title} »`}
preview={`Fermeture ${
buttonTitle ? "d'un lien d'intégration" : "d'un formulaire"
} du service « ${product.title} »`}
baseUrl={baseUrl}
>
<Text style={paragraph}>Bonjour,</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaInviteEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Column, Link, Row, Section, Text } from '@react-email/components';
import { Column, Link, Row, Section, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaNotificationsEmailProps } from './interface';
Expand Down Expand Up @@ -44,17 +44,23 @@ export const JdmaNotificationsEmail = ({
case 'daily':
return `en date du ${formatDate(startDate)}`;
case 'weekly':
return `dans les 7 derniers jours (du ${formatDate(startDate)} au ${formatDate(endDate)})`;
return `dans les 7 derniers jours (du ${formatDate(
startDate
)} au ${formatDate(endDate)})`;
case 'monthly':
return `dans le dernier mois calendaire (du ${formatDate(startDate)} au ${formatDate(endDate)})`;
return `dans le dernier mois calendaire (du ${formatDate(
startDate
)} au ${formatDate(endDate)})`;
default:
return `en date du ${formatDate(startDate)}`;
}
};

return (
<JdmaLayout
preview={`${formatNumber(totalNbReviews)} ${totalNbReviews === 1 ? 'nouvelle réponse' : 'nouvelles réponses'} sur vos services`}
preview={`${formatNumber(totalNbReviews)} ${
totalNbReviews === 1 ? 'nouvelle réponse' : 'nouvelles réponses'
} sur vos services`}
baseUrl={baseUrl}
>
<Text style={paragraph}>Bonjour,</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaOtpEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaProductArchivedEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaProductRestoredEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaTokenEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaTokenEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaUserInviteEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaTokenEmailProps } from './interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, Text } from '@react-email/components';
import { Link, Text } from 'react-email';
import * as React from 'react';
import { JdmaLayout } from './components/JdmaLayout';
import { JdmaUserRequestRefusedEmailProps } from './interface';
Expand Down
Loading
Loading