mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Store an achievement when finishing a tutorial (#6431)
This commit is contained in:
@@ -13,6 +13,10 @@ import {
|
||||
type EditorIdentifier,
|
||||
isMiniTutorial,
|
||||
} from '../Utils/GDevelopServices/InAppTutorial';
|
||||
import {
|
||||
createOrEnsureBadgeForUser,
|
||||
getTutorialCompletedAchievementId,
|
||||
} from '../Utils/GDevelopServices/Badge';
|
||||
import InAppTutorialDialog from './InAppTutorialDialog';
|
||||
import InAppTutorialStepDisplayer from './InAppTutorialStepDisplayer';
|
||||
import { selectMessageByLocale } from '../Utils/i18n/MessageByLocale';
|
||||
@@ -24,8 +28,11 @@ import {
|
||||
isMuiCheckbox,
|
||||
} from '../UI/MaterialUISpecificUtil';
|
||||
import PreferencesContext from '../MainFrame/Preferences/PreferencesContext';
|
||||
import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
||||
import AuthenticatedUserContext, {
|
||||
type AuthenticatedUser,
|
||||
} from '../Profile/AuthenticatedUserContext';
|
||||
import { useScreenType } from '../UI/Responsive/ScreenTypeMeasurer';
|
||||
import { retryIfFailed } from '../Utils/RetryIfFailed';
|
||||
|
||||
const textInterpolationProjectDataAccessors = {
|
||||
instancesCount: 'instancesCount:',
|
||||
@@ -356,6 +363,56 @@ const gatherProjectDataOnMultipleSteps = ({
|
||||
return newData;
|
||||
};
|
||||
|
||||
const useGiveTrivialBadgeWhenTutorialIsFinished = ({
|
||||
authenticatedUser,
|
||||
displayEndDialog,
|
||||
tutorial,
|
||||
}: {
|
||||
authenticatedUser: AuthenticatedUser,
|
||||
displayEndDialog: boolean,
|
||||
tutorial: InAppTutorial,
|
||||
}) => {
|
||||
// Destructure the user data to avoid the effect to run at every change of the user
|
||||
// which is unrelated to badges or the user profile.
|
||||
const {
|
||||
badges,
|
||||
onBadgesChanged,
|
||||
profile,
|
||||
getAuthorizationHeader,
|
||||
} = authenticatedUser;
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
(async () => {
|
||||
if (!profile || !displayEndDialog) return;
|
||||
|
||||
try {
|
||||
// Give a (trivial) badge when a tutorial is finished.
|
||||
await retryIfFailed({ times: 3 }, () =>
|
||||
createOrEnsureBadgeForUser(
|
||||
{ badges, onBadgesChanged, profile, getAuthorizationHeader },
|
||||
getTutorialCompletedAchievementId(tutorial.id)
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Couldn't create completion badge for tutorial ${tutorial.id}.`,
|
||||
error
|
||||
);
|
||||
}
|
||||
})();
|
||||
},
|
||||
[
|
||||
displayEndDialog,
|
||||
badges,
|
||||
onBadgesChanged,
|
||||
profile,
|
||||
getAuthorizationHeader,
|
||||
tutorial.id,
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
tutorial: InAppTutorial,
|
||||
startStepIndex: number,
|
||||
@@ -1065,6 +1122,12 @@ const InAppTutorialOrchestrator = React.forwardRef<
|
||||
[checkIfWrongEditor, currentEditor, currentSceneName]
|
||||
);
|
||||
|
||||
useGiveTrivialBadgeWhenTutorialIsFinished({
|
||||
authenticatedUser,
|
||||
tutorial,
|
||||
displayEndDialog,
|
||||
});
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
import axios from 'axios';
|
||||
import { GDevelopUserApi } from './ApiConfigs';
|
||||
import { type Profile } from './Authentication';
|
||||
|
||||
import { type AuthenticatedUser } from '../../Profile/AuthenticatedUserContext';
|
||||
import { extractGDevelopApiErrorStatusAndCode } from './Errors';
|
||||
@@ -12,6 +13,8 @@ export const TRIVIAL_FIRST_WEB_EXPORT = 'trivial_first-web-export';
|
||||
export const TRIVIAL_FIRST_EXTENSION = 'trivial_first-extension';
|
||||
export const TRIVIAL_FIRST_EFFECT = 'trivial_first-effect';
|
||||
export const TRIVIAL_FIRST_DEBUG = 'trivial_first-debug';
|
||||
export const getTutorialCompletedAchievementId = (tutorialId: string) =>
|
||||
'trivial_in-app-tutorial-completed_' + tutorialId;
|
||||
|
||||
export type Badge = {|
|
||||
seen: boolean,
|
||||
@@ -40,22 +43,26 @@ const isAchievementAlreadyClaimed = (
|
||||
return badges.map(badge => badge.achievementId).includes(achievementId);
|
||||
};
|
||||
|
||||
const createOrEnsureBadgeForUser = async (
|
||||
authenticatedUser: AuthenticatedUser,
|
||||
achievementId: string
|
||||
): Promise<?Badge> => {
|
||||
const {
|
||||
export const createOrEnsureBadgeForUser = async (
|
||||
{
|
||||
badges,
|
||||
firebaseUser,
|
||||
profile,
|
||||
getAuthorizationHeader,
|
||||
onBadgesChanged,
|
||||
} = authenticatedUser;
|
||||
if (!badges || !firebaseUser) return null;
|
||||
}: {
|
||||
badges: ?Array<Badge>,
|
||||
profile: ?Profile,
|
||||
getAuthorizationHeader: () => Promise<string>,
|
||||
onBadgesChanged: () => Promise<void>,
|
||||
},
|
||||
achievementId: string
|
||||
): Promise<?Badge> => {
|
||||
if (!badges || !profile) return null;
|
||||
if (isAchievementAlreadyClaimed(badges, achievementId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const userId = firebaseUser.uid;
|
||||
const userId = profile.id;
|
||||
try {
|
||||
const authorizationHeader = await getAuthorizationHeader();
|
||||
const response = await axios.post(
|
||||
|
Reference in New Issue
Block a user