Skip to content

Commit

Permalink
Addressed review comments
Browse files Browse the repository at this point in the history
Factored out notification useEffect hook, added extra tag for badge messages
  • Loading branch information
Harmit Goswami authored and Harmit Goswami committed Jan 15, 2025
1 parent a0b431c commit ecb761a
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 91 deletions.
11 changes: 7 additions & 4 deletions pontoon/base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,18 @@ def upload(request):

upload = request.FILES["uploadfile"]
try:
badge_update = import_uploaded_file(
badge_name, badge_level = import_uploaded_file(
project, locale, res_path, upload, request.user
)
messages.success(request, "Translations updated from uploaded file.")
if badge_update[0]:
if badge_name:
message = json.dumps(
{"badgeName": badge_update[0], "badgeLevel": badge_update[1]}
{
"name": badge_name,
"level": badge_level,
}
)
messages.info(request, message)
messages.info(request, message, extra_tags="badge")
except Exception as error:
messages.error(request, str(error))
else:
Expand Down
39 changes: 16 additions & 23 deletions pontoon/sync/core/translations_from_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ def sync_translations_from_repo(
def write_db_updates(
project: Project, updates: Updates, user: User | None, now: datetime
) -> tuple[str, int]:
badge_update, updated_translations, new_translations = update_db_translations(
project, updates, user, now
badge_name, badge_level, updated_translations, new_translations = (
update_db_translations(project, updates, user, now)
)
add_failed_checks(new_translations)
add_translation_memory_entries(project, new_translations + updated_translations)
return badge_update
return badge_name, badge_level


def delete_removed_bilingual_resources(
Expand Down Expand Up @@ -435,31 +435,24 @@ def update_db_translations(
f"[{project.slug}] Created {str_n_translations(created)} from repo changes"
)

badge_update = ("", 0)
badge_name = ""
badge_level = 0
if actions:
translation_before_level = log_user.badges_translation_level
review_before_level = log_user.badges_review_level

ActionLog.objects.bulk_create(actions)

if (
log_user.badges_translation_level > translation_before_level
and log_user.username != "pontoon-sync"
):
send_badge_notification(
log_user, "Translation Champion", log_user.badges_translation_level
)
badge_update = ("Translation Champion", log_user.badges_translation_level)
if (
log_user.badges_review_level > review_before_level
and log_user.username != "pontoon-sync"
):
send_badge_notification(
log_user, "Review Master", log_user.badges_review_level
)
badge_update = ("Review Master", log_user.badges_review_level)

return badge_update, created, list(suggestions.values())
if log_user.username != "pontoon-sync":
if log_user.badges_translation_level > translation_before_level:
badge_name = "Translation Champion"
badge_level = log_user.badges_translation_level
send_badge_notification(log_user, badge_name, badge_level)
if log_user.badges_review_level > review_before_level:
badge_name = "Review Master"
badge_level = log_user.badges_review_level
send_badge_notification(log_user, badge_name, badge_level)

return badge_name, badge_level, created, list(suggestions.values())


def str_n_translations(n: int | Sized) -> str:
Expand Down
4 changes: 2 additions & 2 deletions pontoon/sync/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def import_uploaded_file(
)
if updates:
now = timezone.now()
badge_update = write_db_updates(project, updates, user, now)
badge_name, badge_level = write_db_updates(project, updates, user, now)
update_stats(project)
ChangedEntityLocale.objects.bulk_create(
(
Expand All @@ -105,6 +105,6 @@ def import_uploaded_file(
),
ignore_conflicts=True,
)
return badge_update
return badge_name, badge_level
else:
raise Exception("Upload failed.")
44 changes: 6 additions & 38 deletions translate/src/context/BadgeTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,17 @@
import { createContext, useEffect, useState } from 'react';
import { Localized } from '@fluent/react';

export type BadgeTooltipMessage = Readonly<{
badgeName: string | null;
badgeLevel: number | null;
}>;

export const BadgeTooltipMessage = createContext<BadgeTooltipMessage | null>(
null,
);

export const ShowBadgeTooltip = createContext<
(tooltip: BadgeTooltipMessage | null) => void
>(() => {});
import { createContext, useContext } from 'react';
import { BadgeTooltipMessage, ShowBadgeTooltip } from './Notification';

export function BadgeTooltipProvider({
children,
}: {
children: React.ReactElement;
}) {
const [message, setMessage] = useState<BadgeTooltipMessage | null>(null);

useEffect(() => {
const rootElt = document.getElementById('root');
if (rootElt?.dataset.notifications) {
const notifications = JSON.parse(rootElt.dataset.notifications);
if (notifications.length > 0) {
const parsed = notifications.map(
(notification: { content: string; type: string }) => {
if (notification.type === 'info') {
// Badge update information
return JSON.parse(notification.content);
} else {
return { content: notification.content, type: notification.type };
}
},
);
setMessage(parsed[1]);
}
}
}, []);
const badgeMessage = useContext(BadgeTooltipMessage);
const setBadgeMessage = useContext(ShowBadgeTooltip);

return (
<BadgeTooltipMessage.Provider value={message}>
<ShowBadgeTooltip.Provider value={(tooltip) => setMessage(tooltip)}>
<BadgeTooltipMessage.Provider value={badgeMessage}>
<ShowBadgeTooltip.Provider value={setBadgeMessage}>
{children}
</ShowBadgeTooltip.Provider>
</BadgeTooltipMessage.Provider>
Expand Down
40 changes: 22 additions & 18 deletions translate/src/context/Notification.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createContext, useEffect, useState } from 'react';
import React, { createContext } from 'react';
import { useNotifications } from '../hooks/useNotification';

type NotificationType = 'debug' | 'error' | 'info' | 'success' | 'warning';

Expand All @@ -15,32 +16,35 @@ export const ShowNotification = createContext<
(message: NotificationMessage | null) => void
>(() => {});

export type BadgeTooltipMessage = Readonly<{
badgeName: string | null;
badgeLevel: number | null;
}>;

export const BadgeTooltipMessage = createContext<BadgeTooltipMessage | null>(
null,
);

export const ShowBadgeTooltip = createContext<
(tooltip: BadgeTooltipMessage | null) => void
>(() => {});

export function NotificationProvider({
children,
}: {
children: React.ReactElement;
}) {
const [message, setMessage] = useState<NotificationMessage | null>(null);

// If there's a notification in the DOM set by Django, show it.
// Note that we only show it once, and only when the UI has already
// been rendered, to make sure users do see it.
useEffect(() => {
const rootElt = document.getElementById('root');
if (rootElt?.dataset.notifications) {
const notifications = JSON.parse(rootElt.dataset.notifications);
if (notifications.length > 0) {
// Our notification system only supports showing one notification
// for the moment, so we only add the first notification here.
setMessage(notifications[0]);
}
}
}, []);
const { message, setMessage, badgeMessage, setBadgeMessage } =
useNotifications();

return (
<NotificationMessage.Provider value={message}>
<ShowNotification.Provider value={setMessage}>
{children}
<BadgeTooltipMessage.Provider value={badgeMessage}>
<ShowBadgeTooltip.Provider value={setBadgeMessage}>
{children}
</ShowBadgeTooltip.Provider>
</BadgeTooltipMessage.Provider>
</ShowNotification.Provider>
</NotificationMessage.Provider>
);
Expand Down
46 changes: 46 additions & 0 deletions translate/src/hooks/useNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState, useEffect } from 'react';
import {
NotificationMessage,
BadgeTooltipMessage,
} from '../context/Notification';

export function useNotifications() {
const [message, setMessage] = useState<NotificationMessage | null>(null);
const [badgeMessage, setBadgeMessage] = useState<BadgeTooltipMessage | null>(
null,
);

useEffect(() => {
const rootElt = document.getElementById('root');
if (rootElt?.dataset.notifications) {
const notifications = JSON.parse(rootElt.dataset.notifications);
if (notifications.length > 0) {
const generalNotification = notifications.find(
(notification: { type: string }) =>
notification.type !== 'badge info',
);
const badgeNotification = notifications.find(
(notification: { type: string }) =>
notification.type === 'badge info',
);

if (generalNotification) {
setMessage({
type: generalNotification.type,
content: generalNotification.content,
});
}

if (badgeNotification) {
const badgeData = JSON.parse(badgeNotification.content);
setBadgeMessage({
badgeName: badgeData.name || null,
badgeLevel: badgeData.level || null,
});
}
}
}
}, []);

return { message, setMessage, badgeMessage, setBadgeMessage };
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Localized } from '@fluent/react';
import React, { useCallback, useContext, useEffect, useRef } from 'react';

import { Location } from '~/context/Location';
import { ShowBadgeTooltip } from '~/context/BadgeTooltip';
import { ShowBadgeTooltip } from '~/context/Notification';
import { useAppDispatch, useAppSelector } from '~/hooks';

import { performAction, resetSelection, selectAll } from '../actions';
Expand Down
2 changes: 1 addition & 1 deletion translate/src/modules/editor/components/BadgeTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useCallback, useContext, useRef } from 'react';
import { Localized } from '@fluent/react';
import Pride from 'react-canvas-confetti/dist/presets/pride';

import { BadgeTooltipMessage, ShowBadgeTooltip } from '~/context/BadgeTooltip';
import { BadgeTooltipMessage, ShowBadgeTooltip } from '~/context/Notification';
import { useAppSelector } from '~/hooks';
import { useOnDiscard } from '~/utils';

Expand Down
3 changes: 1 addition & 2 deletions translate/src/modules/editor/hooks/useSendTranslation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { EntityView } from '~/context/EntityView';
import { FailedChecksData } from '~/context/FailedChecksData';
import { Locale } from '~/context/Locale';
import { Location } from '~/context/Location';
import { ShowNotification } from '~/context/Notification';
import { UnsavedActions } from '~/context/UnsavedChanges';
import { updateEntityTranslation } from '~/modules/entities/actions';
import { usePushNextTranslatable } from '~/modules/entities/hooks';
Expand All @@ -23,7 +22,7 @@ import { updateResource } from '~/modules/resource/actions';
import { updateStats } from '~/modules/stats/actions';
import { useAppDispatch, useAppSelector } from '~/hooks';
import { serializeEntry, getPlainMessage } from '~/utils/message';
import { ShowBadgeTooltip } from '~/context/BadgeTooltip';
import { ShowBadgeTooltip, ShowNotification } from '~/context/Notification';

/**
* Return a function to send a translation to the server.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import { EntityView } from '~/context/EntityView';
import { FailedChecksData } from '~/context/FailedChecksData';
import { HistoryData } from '~/context/HistoryData';
import { Location } from '~/context/Location';
import { ShowNotification } from '~/context/Notification';
import { ShowBadgeTooltip } from '~/context/BadgeTooltip';
import { ShowBadgeTooltip, ShowNotification } from '~/context/Notification';
import { updateEntityTranslation } from '~/modules/entities/actions';
import { usePushNextTranslatable } from '~/modules/entities/hooks';
import {
Expand Down

0 comments on commit ecb761a

Please sign in to comment.