feat: test publish to youtube
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import { Image } from "expo-image";
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { Linking, Text, View } from "react-native";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||
import { ai, background } from "../../assets";
|
||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import firebase, { projectsRef, serverTimestamp } from "../../config/firebase";
|
||||
import Page from "../../layouts/Page";
|
||||
import { goBack } from "../../navigation/NavigationService";
|
||||
import { useUser } from "../../providers/UserDataProvider";
|
||||
import { Palette, gutters } from "../../styles";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
|
||||
const PublishYoutube = () => {
|
||||
const route = useRoute();
|
||||
const routeProjectId = route?.params?.projectId ?? null;
|
||||
const { userProjects = [], selectedProject } = useUser();
|
||||
const { setTooltip } = useMinuit();
|
||||
|
||||
const project = useMemo(() => {
|
||||
if (routeProjectId) {
|
||||
return (
|
||||
userProjects.find((item) => item?.id === routeProjectId) ||
|
||||
selectedProject ||
|
||||
null
|
||||
);
|
||||
}
|
||||
if (selectedProject?.id) {
|
||||
return selectedProject;
|
||||
}
|
||||
return userProjects.length ? userProjects[0] : null;
|
||||
}, [routeProjectId, selectedProject, userProjects]);
|
||||
|
||||
const projectId = project?.id || routeProjectId || null;
|
||||
|
||||
const [saving, setSaving] = useState(false);
|
||||
const youtubeUrl = project?.youtubeUrl ?? null;
|
||||
const youtubeStatus = project?.youtubeStatus ?? null;
|
||||
const youtubeError = project?.youtubeError ?? null;
|
||||
const playbackReady = !!project?.playbackUrl;
|
||||
const hasYoutubePublication = !!youtubeUrl;
|
||||
const isPublishing = useMemo(
|
||||
() =>
|
||||
["PUBLISHING", "UPLOADING", "PROCESSING", "QUEUED"].includes(
|
||||
youtubeStatus
|
||||
),
|
||||
[youtubeStatus]
|
||||
);
|
||||
const publishDisabled =
|
||||
saving || isPublishing || !playbackReady || !projectId;
|
||||
const publishButtonLabel = isPublishing
|
||||
? "Publication en cours..."
|
||||
: hasYoutubePublication
|
||||
? "Mettre à jour sur YouTube"
|
||||
: "Publier sur YouTube";
|
||||
const statusMessage = useMemo(() => {
|
||||
if (!playbackReady) {
|
||||
return "Termine la création de ton playback avec John pour débloquer la publication YouTube.";
|
||||
}
|
||||
if (isPublishing) {
|
||||
return "Bena s'occupe de mettre ta vidéo en ligne... Patiente un instant.";
|
||||
}
|
||||
if (youtubeError || youtubeStatus === "FAILED") {
|
||||
return "La dernière tentative de publication a échoué. Tu peux réessayer ci-dessous.";
|
||||
}
|
||||
if (hasYoutubePublication) {
|
||||
return "Ta vidéo est publiée sur la chaîne YouTube MusicLand. Tu peux la partager dès maintenant.";
|
||||
}
|
||||
return "Bena t’accompagne pour partager ton playback sur la chaîne YouTube MusicLand.";
|
||||
}, [
|
||||
hasYoutubePublication,
|
||||
isPublishing,
|
||||
playbackReady,
|
||||
youtubeError,
|
||||
youtubeStatus,
|
||||
]);
|
||||
|
||||
const handleOpenYoutube = useCallback(async () => {
|
||||
if (!youtubeUrl) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await Linking.openURL(youtubeUrl);
|
||||
} catch (_error) {
|
||||
setTooltip?.({
|
||||
type: "error",
|
||||
text: "Impossible d'ouvrir le lien YouTube",
|
||||
});
|
||||
}
|
||||
}, [setTooltip, youtubeUrl]);
|
||||
|
||||
const handleMarkPublished = useCallback(async () => {
|
||||
if (!projectId) {
|
||||
setTooltip?.({
|
||||
type: "error",
|
||||
text: "Sélectionnez un projet avant de publier",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!playbackReady) {
|
||||
setTooltip?.({
|
||||
type: "error",
|
||||
text: "Aucun playback n'est disponible pour la publication",
|
||||
});
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
try {
|
||||
const publishCallable = firebase
|
||||
.functions()
|
||||
.httpsCallable("publishPlaybackToYoutube");
|
||||
await publishCallable({ projectId });
|
||||
setTooltip?.({
|
||||
type: "success",
|
||||
text: "Publication lancée sur YouTube",
|
||||
});
|
||||
} catch (error) {
|
||||
setTooltip?.({
|
||||
type: "error",
|
||||
text: error?.message || "Impossible de lancer la publication",
|
||||
});
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [playbackReady, projectId, setTooltip]);
|
||||
|
||||
const handleResetPublication = useCallback(async () => {
|
||||
if (!projectId) {
|
||||
setTooltip?.({
|
||||
type: "error",
|
||||
text: "Sélectionnez un projet avant de réinitialiser",
|
||||
});
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
try {
|
||||
await projectsRef.doc(projectId).set(
|
||||
{
|
||||
youtubePublished: false,
|
||||
youtubeUrl: null,
|
||||
youtubeVideoId: null,
|
||||
youtubePublishedAt: null,
|
||||
youtubeStatus: "IDLE",
|
||||
youtubeError: null,
|
||||
updatedAt: serverTimestamp(),
|
||||
},
|
||||
{ merge: true }
|
||||
);
|
||||
setTooltip?.({
|
||||
type: "success",
|
||||
text: "Publication YouTube réinitialisée",
|
||||
});
|
||||
} catch (error) {
|
||||
setTooltip?.({
|
||||
type: "error",
|
||||
text: error?.message || "Réinitialisation impossible",
|
||||
});
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [projectId, setTooltip]);
|
||||
|
||||
return (
|
||||
<Page backgroundImg={background.playbackBG2} headerType="NONE">
|
||||
<MusicLandHeader progress={100} onPressBack={goBack} />
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
paddingHorizontal: gutters,
|
||||
paddingBottom: gutters * 2,
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<View style={{ alignItems: "center", gap: 18 }}>
|
||||
<Image
|
||||
source={ai.bena}
|
||||
style={{ width: 220, height: 320 }}
|
||||
contentFit="contain"
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 22,
|
||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||
color: Palette.white,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{hasYoutubePublication
|
||||
? "Ta vidéo est déjà sur YouTube"
|
||||
: "Publier sur YouTube"}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 14,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
color: Palette.white,
|
||||
opacity: 0.9,
|
||||
textAlign: "center",
|
||||
lineHeight: 20,
|
||||
}}
|
||||
>
|
||||
{statusMessage}
|
||||
</Text>
|
||||
{youtubeError && (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 13,
|
||||
fontFamily: FONT_FAMILY.InterRegular,
|
||||
color: Palette.red,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{youtubeError}
|
||||
</Text>
|
||||
)}
|
||||
{hasYoutubePublication && youtubeUrl && (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 13,
|
||||
fontFamily: FONT_FAMILY.InterMedium,
|
||||
color: Palette.white,
|
||||
textAlign: "center",
|
||||
opacity: 0.8,
|
||||
}}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{youtubeUrl}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<View style={{ gap: 14 }}>
|
||||
<GradientButton
|
||||
title={publishButtonLabel}
|
||||
onPress={handleMarkPublished}
|
||||
disabled={publishDisabled}
|
||||
/>
|
||||
|
||||
{hasYoutubePublication && youtubeUrl && (
|
||||
<BorderGradientButton
|
||||
title="Voir la vidéo sur YouTube"
|
||||
onPress={handleOpenYoutube}
|
||||
disabled={saving || isPublishing}
|
||||
/>
|
||||
)}
|
||||
{hasYoutubePublication && (
|
||||
<BorderGradientButton
|
||||
title="Réinitialiser la publication"
|
||||
onPress={handleResetPublication}
|
||||
disabled={saving || isPublishing}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublishYoutube;
|
||||
Reference in New Issue
Block a user