import AsyncStorage from '@react-native-community/async-storage'; import RNFetchBlob from 'rn-fetch-blob'; import { CHECK_MOMENT_UPLOAD_DONE_PROCESSING_ENDPOINT, MOMENTS_ENDPOINT, MOMENTTAG_ENDPOINT, MOMENT_TAGS_ENDPOINT, MOMENT_THUMBNAIL_ENDPOINT, MOMENT_VIEW_COUNT_API, PRESIGNED_URL_ENDPOINT, TAGG_CUSTOMER_SUPPORT, } from '../constants'; import { ERROR_SOMETHING_WENT_WRONG, ERROR_SOMETHING_WENT_WRONG_REFRESH, } from '../constants/strings'; import {MomentPostType, MomentTagType, PresignedURLResponse} from '../types'; import {checkImageUploadStatus} from '../utils'; export const postMoment = async ( uri: string, caption: string, category: string, ) => { try { const request = new FormData(); const fileExtension = uri.split('.').pop(); const extension = fileExtension ? `.${fileExtension}` : '.jpg'; request.append('image', { uri: uri, name: Math.random().toString(36).substring(7) + extension, type: 'image/jpg', }); request.append('moment', category); request.append('captions', JSON.stringify({image: caption})); const token = await AsyncStorage.getItem('token'); let response = await fetch(MOMENTS_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'multipart/form-data', Authorization: 'Token ' + token, }, body: request, }); let statusCode = response.status; let data: { moments: any; moment_id: string; profile_completion_stage: number; } = await response.json(); if (statusCode === 200 && checkImageUploadStatus(data.moments)) { return data; } } catch (err) { console.log(err); } return undefined; }; export const patchMoment = async ( momentId: string, caption: string, category: string, tags: { x: number; y: number; z: number; user_id: string; }[], ) => { try { const request = new FormData(); request.append('moment_id', momentId); request.append('caption', caption); request.append('category', category); request.append('tags', JSON.stringify(tags)); const token = await AsyncStorage.getItem('token'); let response = await fetch(MOMENTS_ENDPOINT, { method: 'PATCH', headers: { 'Content-Type': 'multipart/form-data', Authorization: 'Token ' + token, }, body: request, }); let statusCode = response.status; return statusCode === 200 || statusCode === 201; } catch (err) { console.log(err); } return false; }; export const loadMoments = async (userId: string, token: string) => { try { const response = await fetch(MOMENTS_ENDPOINT + '?user_id=' + userId, { method: 'GET', headers: { Authorization: 'Token ' + token, }, }); if (response.status === 200) { const typedData: MomentPostType[] = await response.json(); return typedData; } } catch (err) { console.log(err); } return []; }; export const deleteMoment = async (momentId: string) => { try { const token = await AsyncStorage.getItem('token'); const response = await fetch(MOMENTS_ENDPOINT + `${momentId}/`, { method: 'DELETE', headers: { Authorization: 'Token ' + token, }, }); return response.status === 200; } catch (error) { console.log(error); console.log('Unable to delete moment', momentId); return false; } }; export const loadMomentThumbnail = async (momentId: string) => { try { const token = await AsyncStorage.getItem('token'); const response = await RNFetchBlob.config({ fileCache: false, appendExt: 'jpg', }).fetch('GET', MOMENT_THUMBNAIL_ENDPOINT + `${momentId}/`, { Authorization: 'Token ' + token, }); const status = response.info().status; if (status === 200) { return response.path(); } else { return undefined; } } catch (error) { console.log(error); return undefined; } }; export const loadMomentTags = async (moment_id: string) => { try { const token = await AsyncStorage.getItem('token'); const response = await fetch( MOMENT_TAGS_ENDPOINT + `?moment_id=${moment_id}`, { method: 'GET', headers: { Authorization: 'Token ' + token, }, }, ); if (response.status === 200) { const tags: MomentTagType[] = await response.json(); return tags; } } catch (error) { console.error(error); return []; } }; export const postMomentTags = async ( moment_id: string, tags: { x: number; y: number; z: number; user_id: string; }[], ) => { try { const token = await AsyncStorage.getItem('token'); const form = new FormData(); form.append('moment_id', moment_id); form.append('tags', JSON.stringify(tags)); const response = await fetch(MOMENTTAG_ENDPOINT, { method: 'POST', headers: { Authorization: 'Token ' + token, }, body: form, }); return response.status === 201 || response.status === 200; } catch (error) { console.error(error); return false; } }; export const deleteMomentTag = async (moment_tag_id: string) => { try { const token = await AsyncStorage.getItem('token'); const response = await fetch(MOMENTTAG_ENDPOINT + `${moment_tag_id}/`, { method: 'DELETE', headers: { Authorization: 'Token ' + token, }, }); return response.status === 200; } catch (error) { console.error(error); return false; } }; /** * This function makes a request to the server in order to provide the client with a presigned URL. * This is called first, in order for the client to directly upload a file to S3 * @param value: string | undefined * @returns a PresignedURLResponse object */ export const handlePresignedURL = async ( caption: string, momentCategory: string, ) => { try { // TODO: just a random filename for video poc, we should not need to once complete const randHash = Math.random().toString(36).substring(7); const filename = `pc_${randHash}.mov`; const token = await AsyncStorage.getItem('token'); const response = await fetch(PRESIGNED_URL_ENDPOINT, { method: 'POST', headers: { Authorization: 'Token ' + token, }, body: JSON.stringify({ filename, caption: caption, category: momentCategory, }), }); const status = response.status; let data: PresignedURLResponse = await response.json(); if (status === 200) { return data; } else { if (status === 404) { console.log( `Please make sure that the email / username entered is registered with us. You may contact our customer support at ${TAGG_CUSTOMER_SUPPORT}`, ); } else { console.log(ERROR_SOMETHING_WENT_WRONG_REFRESH); } console.log(response); } } catch (error) { console.log(error); console.log(ERROR_SOMETHING_WENT_WRONG); } }; /** * This util function takes in the file object and the PresignedURLResponse object, creates form data from the latter, * and makes a post request to the presigned URL, sending the file object inside of the form data. * @param filePath: the path to the file, including filename * @param urlObj PresignedURLResponse | undefined * @returns responseURL or boolean */ export const handleVideoUpload = async ( filePath: string, urlObj: PresignedURLResponse | undefined, ) => { try { if (urlObj === null || urlObj === undefined) { console.log('Invalid urlObj'); return false; } const form = new FormData(); form.append('key', urlObj.response_url.fields.key); form.append( 'x-amz-algorithm', urlObj.response_url.fields['x-amz-algorithm'], ); form.append( 'x-amz-credential', urlObj.response_url.fields['x-amz-credential'], ); form.append('x-amz-date', urlObj.response_url.fields['x-amz-date']); form.append('policy', urlObj.response_url.fields.policy); form.append( 'x-amz-signature', urlObj.response_url.fields['x-amz-signature'], ); form.append('file', { uri: filePath, // other types such as 'quicktime' 'image' etc exist, and we can programmatically type this, but for now sticking with simple 'video' type: 'video', name: urlObj.response_url.fields.key, }); const response = await fetch(urlObj.response_url.url, { method: 'POST', headers: { 'Content-Type': 'multipart/form-data', }, body: form, }); const status = response.status; if (status === 200 || status === 204) { console.log('complete'); return true; } else { if (status === 404) { console.log( `Please make sure that the email / username entered is registered with us. You may contact our customer support at ${TAGG_CUSTOMER_SUPPORT}`, ); } else { console.log(ERROR_SOMETHING_WENT_WRONG_REFRESH); } } } catch (error) { console.log(error); console.log(ERROR_SOMETHING_WENT_WRONG); } return false; }; /* * Records a view on a moment */ export const increaseMomentViewCount = async (moment_id: string) => { const token = await AsyncStorage.getItem('token'); const response = await fetch(MOMENT_VIEW_COUNT_API + `${moment_id}/`, { method: 'PATCH', headers: { Authorization: 'Token ' + token, }, }); if (response.status === 200) { const {view_count} = await response.json(); return view_count; } return; }; export const checkMomentDoneProcessing = async (momentId: string) => { try { const token = await AsyncStorage.getItem('token'); const response = await fetch( CHECK_MOMENT_UPLOAD_DONE_PROCESSING_ENDPOINT + '?moment_id=' + momentId, { method: 'GET', headers: { Authorization: 'Token ' + token, }, }, ); return response.status === 200; } catch (error) { console.error(error); return false; } };