Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,40 @@ import {
View,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useGenerateTemplateFromTikTok } from '../hooks';
import { useGenerateTemplateFromOnlineContent } from '../hooks';

interface TikTokImportModalProps {
visible: boolean;
onClose: () => void;
}

export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps) {
export function OnlineContentImportModal({ visible, onClose }: TikTokImportModalProps) {
const { t } = useTranslation();
const { colors } = useColorScheme();
const router = useRouter();
const [tiktokUrl, setTiktokUrl] = useState('');
const [onlineContentUrl, setOnlineContentUrl] = useState('');

const { mutate: generateTemplate, isPending } = useGenerateTemplateFromTikTok();
const { mutate: generateTemplate, isPending } = useGenerateTemplateFromOnlineContent();

const handleGenerate = () => {
if (!tiktokUrl.trim()) {
if (!onlineContentUrl.trim()) {
Burnt.toast({
title: t('packTemplates.tiktokUrlRequired'),
title: t('packTemplates.onlineContentUrlRequired'),
preset: 'error',
});
return;
}

generateTemplate(
{
tiktokUrl: tiktokUrl.trim(),
contentUrl: onlineContentUrl.trim(),
isAppTemplate: true,
},
{
onSuccess: (template) => {
onClose();
Burnt.toast({
title: t('packTemplates.tiktokImportSuccess'),
title: t('packTemplates.onlineContentImportSuccess'),
preset: 'done',
});
router.push({
Expand All @@ -56,7 +56,7 @@ export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps)
});
},
onError: (error) => {
console.error('TikTok import error:', error);
console.error('Online content import error:', error);

// Handle duplicate template case - navigate to existing template
if (error.code === 'DUPLICATE_TEMPLATE' && error.existingTemplateId) {
Expand All @@ -73,7 +73,7 @@ export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps)
}

// Handle other errors
const errorMessage = error.message || t('packTemplates.tiktokImportError');
const errorMessage = error.message || t('packTemplates.onlineContentImportError');
Burnt.toast({
title: t('packTemplates.importFailed'),
message: errorMessage,
Expand All @@ -85,7 +85,7 @@ export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps)
};

const handleClose = () => {
setTiktokUrl('');
setOnlineContentUrl('');
onClose();
};

Expand All @@ -108,7 +108,7 @@ export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps)
<Icon name="close" size={24} color={colors.foreground} />
</TouchableOpacity>
<Text className="text-lg font-semibold text-foreground">
{t('packTemplates.importFromTikTok')}
{t('packTemplates.importFromOnlineContent')}
</Text>
<View className="w-8" />
</View>
Expand All @@ -117,19 +117,19 @@ export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps)
<View className="flex-1 px-4 py-6">
<View className="mb-6">
<Text className="text-base text-muted-foreground leading-6 mb-4">
{t('packTemplates.tiktokImportDescription')}
{t('packTemplates.onlineContentImportDescription')}
</Text>
</View>

{/* TikTok URL Input */}
{/* Online Content URL Input */}
<View className="mb-6">
<Text className="mb-3 text-sm font-medium text-foreground">
{t('packTemplates.tiktokUrl')}
{t('packTemplates.onlineContentUrl')}
</Text>
<TextField
placeholder={t('packTemplates.tiktokUrlPlaceholder')}
value={tiktokUrl}
onChangeText={setTiktokUrl}
placeholder={t('packTemplates.onlineContentUrlPlaceholder')}
value={onlineContentUrl}
onChangeText={setOnlineContentUrl}
autoCapitalize="none"
autoCorrect={false}
keyboardType="url"
Expand All @@ -150,8 +150,8 @@ export function TikTokImportModal({ visible, onClose }: TikTokImportModalProps)
{isPending && <ActivityIndicator size="small" color="white" />}
<Text className="text-base font-semibold text-white">
{isPending
? t('packTemplates.generatingFromTikTok')
: t('packTemplates.generateFromTikTok')}
? t('packTemplates.generatingFromOnlineContent')
: t('packTemplates.generateFromOnlineContent')}
</Text>
</TouchableOpacity>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useRouter } from 'expo-router';
import React, { useState } from 'react';
import { TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { TikTokImportModal } from './TikTokImportModal';
import { OnlineContentImportModal } from './OnlineContentImportModal';

type TemplateCreationOptionsProps = object;

Expand All @@ -23,7 +23,7 @@ export default React.forwardRef<BottomSheetModal, TemplateCreationOptionsProps>(
const { isAuthenticated } = useAuth();
const user = useUser();
const isAdmin = user?.role === 'ADMIN';
const [showTikTokModal, setShowTikTokModal] = useState(false);
const [showOnlineContentModal, setShowOnlineContentModal] = useState(false);
const insets = useSafeAreaInsets();

const { run, handleDismiss } = useBottomSheetAction(ref as React.RefObject<BottomSheetModal>);
Expand All @@ -34,9 +34,9 @@ export default React.forwardRef<BottomSheetModal, TemplateCreationOptionsProps>(
});
};

const handleImportFromTikTok = () => {
const handleImportFromOnlineContent = () => {
run(() => {
setShowTikTokModal(true);
setShowOnlineContentModal(true);
});
};

Expand Down Expand Up @@ -83,18 +83,18 @@ export default React.forwardRef<BottomSheetModal, TemplateCreationOptionsProps>(
{/* Import from TikTok option (only for admins) */}
{isAdmin && isAuthenticated && (
<TouchableOpacity
onPress={handleImportFromTikTok}
onPress={handleImportFromOnlineContent}
className="rounded-lg border border-border bg-card p-4 flex-row items-center"
>
<View className="mr-4 rounded-full bg-primary/10 p-3">
<Icon name="link" size={24} color={colors.primary} />
</View>
<View className="flex-1">
<Text className="text-base font-semibold text-foreground mb-1">
{t('packTemplates.importFromTikTok')}
{t('packTemplates.importFromOnlineContent')}
</Text>
<Text className="text-sm text-muted-foreground">
{t('packTemplates.importFromTikTokDescription')}
{t('packTemplates.importFromOnlineContentDescription')}
</Text>
</View>
<Icon name="chevron-right" size={20} color={colors.grey3} />
Expand All @@ -103,8 +103,10 @@ export default React.forwardRef<BottomSheetModal, TemplateCreationOptionsProps>(
</BottomSheetView>
</Sheet>

{/* TikTok Import Modal */}
<TikTokImportModal visible={showTikTokModal} onClose={() => setShowTikTokModal(false)} />
<OnlineContentImportModal
visible={showOnlineContentModal}
onClose={() => setShowOnlineContentModal(false)}
/>
</>
);
},
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/features/pack-templates/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export * from './useCreatePackTemplate';
export * from './useCreatePackTemplateItem';
export * from './useDeletePackTemplate';
export * from './useDeletePackTemplateItem';
export * from './useGenerateTemplateFromTikTok';
export * from './useGenerateTemplateFromOnlineContent';
export * from './usePackTemplateItem';
export * from './usePackTemplates';
export * from './usePackTemplatesDetails';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { packTemplateItemsStore } from '../store/packTemplateItems';
import { packTemplatesStore } from '../store/packTemplates';
import type { PackTemplateInStore } from '../types';

export interface GenerateFromTikTokInput {
tiktokUrl: string;
export interface GenerateFromOnlineContentInput {
contentUrl: string;
name?: string;
category?: string;
isAppTemplate?: boolean;
Expand Down Expand Up @@ -33,18 +33,18 @@ export interface GeneratedTemplate extends PackTemplateInStore {
}>;
}

export interface TikTokImportError extends Error {
export interface ImportError extends Error {
status?: number;
code?: string;
existingTemplateId?: string;
}

export function useGenerateTemplateFromTikTok() {
return useMutation<GeneratedTemplate, TikTokImportError, GenerateFromTikTokInput>({
export function useGenerateTemplateFromOnlineContent() {
return useMutation<GeneratedTemplate, ImportError, GenerateFromOnlineContentInput>({
mutationFn: async (input) => {
try {
const response = await axiosInstance.post(
'/api/pack-templates/generate-from-tiktok',
'/api/pack-templates/generate-from-online-content',
input,
{ timeout: 0 },
);
Expand Down Expand Up @@ -73,12 +73,12 @@ export function useGenerateTemplateFromTikTok() {
}
}

const tikTokError = new Error(message) as TikTokImportError;
tikTokError.status = status;
tikTokError.code = errorCode;
tikTokError.existingTemplateId = existingTemplateId;
const importError = new Error(message) as ImportError;
importError.status = status;
importError.code = errorCode;
importError.existingTemplateId = existingTemplateId;

throw tikTokError;
throw importError;
}
},
onSuccess: (data) => {
Expand Down
26 changes: 13 additions & 13 deletions apps/expo/lib/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -837,21 +837,21 @@
"markAsAppTemplate": "Mark as Featured Template",
"appTemplateFootnote": "Featured templates are shown to all users. Option is only available to admins.",
"appTemplate": "Featured",
"importFromTikTok": "Import from TikTok",
"importFromTikTokDescription": "Import gear from a TikTok video or slideshow post",
"tiktokUrl": "TikTok URL",
"tiktokUrlPlaceholder": "https://www.tiktok.com/@user/video/...",
"generateFromTikTok": "Generate Template",
"generatingFromTikTok": "Generating...",
"tiktokUrlRequired": "TikTok URL is required",
"tiktokImportSuccess": "Pack template created successfully!",
"tiktokImportError": "Failed to generate template from TikTok. Please try again.",
"importFromOnlineContent": "Import from Online Content",
"importFromOnlineContentDescription": "Supports YouTube and TikTok videos or slideshow posts",
"onlineContentUrl": "Content URL",
"onlineContentUrlPlaceholder": "https://www.tiktok.com/@user/video/...",
"generateFromOnlineContent": "Generate Template",
"generatingFromOnlineContent": "Generating...",
"onlineContentUrlRequired": "Content URL is required",
"onlineContentImportSuccess": "Pack template created successfully!",
"onlineContentImportError": "Failed to generate template.",
"templateAlreadyExists": "Template Already Exists",
"importFailed": "Import Failed",
"tiktokImportDuplicateError": "A template already exists for this content.",
"tiktokImportServiceError": "TikTok service is unavailable. Please try again later.",
"tiktokImportAIError": "AI analysis failed. Please try again or contact support.",
"tiktokImportDescription": "Paste a TikTok video or slideshow URL below. AI will identify items and build a pack template using our catalog.",
"onlineContentImportDuplicateError": "A template already exists for this content.",
"onlineContentImportServiceError": "Service unavailable.",
"onlineContentImportAIError": "AI analysis failed. Please try again or contact support.",
"onlineContentImportDescription": "Paste a Youtube, TikTok video or slideshow URL below. AI will identify items and build a pack template using our catalog.",
"viewExistingTemplate": "View",
"creating": "Creating...",
"updating": "Updating...",
Expand Down
11 changes: 7 additions & 4 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"resend": "^4.2.0",
"workers-ai-provider": "^0.7.2",
"ws": "^8.18.1",
"youtube-transcript": "^1.3.0",
"zod": "^3.24.2",
"zod-openapi": "^4.2.4"
},
Expand Down
Loading
Loading