{"version":3,"sources":["utils/video.ts","utils/authClient.ts","utils/auth.tsx","utils/updateHead.ts","utils/index.ts","utils/canister.ts","components/Video.tsx","components/ProfilePic.tsx","../.dfx/ic/canisters/CanCan/CanCan.did.js","../.dfx/ic/canisters/CanCan/CanCan.js","utils/canister/actor.ts","components/LottieAnimation.tsx","components/SearchVideoItem.tsx","components/SuperLikeEffect.tsx","assets/images/icon-like.png","assets/images/icon-comment.png","assets/images/icon-share.png","components/FlagButton.tsx","assets/images/icon-report.png","components/SuperLikeButton.tsx","assets/images/icon-superlike.png","assets/images/icon-tip-active.png","components/TippingButton.tsx","assets/images/cancan-logo.png","views/SignIn.tsx","components/LoadingIndicator.tsx","components/SignUp.tsx","views/Feed.tsx","views/Discover.tsx","components/Upload.tsx","assets/images/rewards-view.png","views/Rewards.tsx","components/FollowButton.tsx","components/FollowUserRow.tsx","assets/images/icon-back.png","views/Profile.tsx","assets/images/icon-rewards.png","components/DropDayNotification.tsx","assets/images/icon-tokens.png","assets/images/icon-close.png","components/RewardShowerNotification.tsx","components/MainNav.tsx","assets/images/icon-home.png","assets/images/icon-discover.png","assets/images/icon-upload.png","assets/images/icon-profile.png","components/PrivateRoutes.tsx","AppRouter.tsx","index.tsx"],"names":["async","processAndUploadChunk","videoBuffer","byteStart","videoSize","videoId","chunk","videoSlice","slice","Math","min","MAX_CHUNK_SIZE","sliceToNat","encodeArrayBuffer","putVideoChunk","uploadVideo","userId","file","caption","arrayBuffer","ArrayBuffer","videoInit","chunkCount","Number","ceil","size","createdAt","Date","now","name","replace","tags","match","hashtagRegExp","getVideoInit","createVideo","thumb","videoFile","videoElement","document","createElement","thumbnailCanvas","canvasContext","getContext","videoUrl","URL","createObjectURL","src","addEventListener","width","videoWidth","height","videoHeight","Promise","resolve","reject","drawImage","revokeObjectURL","toBlob","canvasBlob","then","Uint8Array","setTimeout","currentTime","generateThumbnail","console","log","putVideoPic","error","uploadVideoPic","putChunkPromises","push","all","resultFromCanCan","getVideoInfo","Error","checkVidFromIC","useUploadVideo","completedVideo","setCompletedVideo","useState","setFile","setCaption","ready","setReady","useEffect","undefined","fileToUpload","info","time","video","timeEnd","handleUpload","IDENTITY_URL","URLSearchParams","location","search","get","process","REACT_APP_INTERNET_IDENTITY_URL","authClient","constructor","this","AuthClient","create","isAuthenticated","login","identityProvider","onSuccess","getIdentity","logout","returnTo","authContext","createContext","ProvideAuth","children","auth","user","setUser","isAuthenticatedLocal","setIsAuthenticatedLocal","_identity","_setIdentity","isAuthClientReady","setAuthClientReady","urlWithSearch","globalThis","identity","getPrincipal","isAnonymous","actorController","authenticateActor","unauthenticateActor","isAuthReady","isReady","hasCanCanAccount","logIn","logOut","localStorage","removeItem","KEY_LOCALSTORAGE_USER","useProvideAuth","authenticationClient","Provider","value","useAuth","useContext","APP_TITLE","updates","el","attrs","content","updateHead","title","forEach","update","Object","entries","attr","head","appendChild","REWARDS_CHECK_INTERVAL","Array","from","unwrap","val","formatBigNumber","number","toFixed","fileToImgSrc","imgType","byteArray","picBlob","Blob","type","textToColor","text","numStringFromString","split","map","char","charCodeAt","join","hexFromNumString","parseInt","toString","trimAmount","length","i","abs","startIndex","hexArray","CanCan","getUserNameByPrincipal","principal","actor","createUser","profile","createProfile","JSON","stringify","isDropDay","Boolean","getUserFromCanister","icUser","getProfilePlus","getSearchVideos","terms","limit","videos","v","getFeedVideos","videoInfo","getProfilePic","follow","userToFollow","follower","willFollow","putProfileFollow","like","willLike","putProfileVideoLike","superLike","willSuperLike","putSuperLike","getVideoChunks","chunkBuffers","chunksAsPromises","getVideoChunk","filter","bytes","bytesAsBuffer","Buffer","videoBlob","concat","chunkNum","chunkData","getVideoPic","icResponse","pic","checkUsername","username","checkUsernameAvailable","getMessages","putRewardTransfer","sender","recipient","amount","putAbuseFlagVideo","reporter","target","shouldFlag","Video","props","isPreview","userRewardPoints","onRefreshUser","onClose","className","VideoBase","play","setPlay","videoSourceURL","setVideoSourceURL","userPic","setUserPic","userLikes","setUserLikes","likes","includes","isSuperLiked","setIsSuperLiked","superLikes","videoIsFlagged","abuseFlagCount","videoRef","useRef","blobURL","current","pause","isCurrentUser","videoBlurStyle","isActive","onClick","aria-label","ref","loop","muted","autoPlay","style","profilePic","position","to","id","disabled","handleSuperLike","senderId","currentRewardPoints","recipientId","state","display","likeIcon","alt","commentIcon","comments","some","comment","shareIcon","shares","currentUserId","ProfilePic","profileColor","backgroundColor","idlFactory","IDL","ProfilePic_2","Vec","Nat8","VideoPic_2","Timestamp","Int","UserId","Text","VideoId_2","VideoInfo_2","Record","Opt","Nat","Bool","AllowanceBalance","Variant","Null","UserAllowances","ProfileInfo_2","ProfileInfoPlus","UserId_2","VideoId","VideoInit_2","VideoInit","VideoId_3","UserId_3","VideosPred","TimeMode","Command","Tuple","Result","TraceCommand","Trace","UserAction","ActionTarget","Check","Principal","Event_3","LikeVideo","AbuseFlag","SuperLikeVideoFail","SuperLikeVideo","RewardPointTransfer","CreateVideo","CreateProfile","ViralVideoSuperLiker","ViralVideo","Signal","EventKind","Event_2","VideoResult","VideoResults","Event","Message","ProfileInfo","VideoInfo","VideoPic","Service","Func","isLocalEnv","DFX_NETWORK","createActor","agent","HttpAgent","host","Actor","CanCan_idl","canisterId","_actor","_isAuthenticated","initBaseActor","fetchRootKey","LottieAnimation","animation","animationData","SearchVideoItem","setPic","picAsNum","bufferBlob","SuperLikeEffect","mainAnimActive","setMainAnimActive","secondAnimActive","setSecondAnimActive","timeoutMain","timeoutSecondary","clearTimeout","animationPosition","x","y","window","innerHeight","iconPositionInAnimation","animationStyling","transform","SuperLikeAnim","SuperLikeAnimIcon","FlagButton","localFlags","setLocalFlags","setActive","viewerHasFlagged","isDisabled","pointerEvents","cursor","SuperLikeButton","data-test-id","TippingButton","setDisabled","activeAnimations","setActiveAnimations","animationId","setAnimationId","localRewardPoints","setRewardPoints","tippingPoints","setTippingPoints","saveTippingDebounced","debounce","BigInt","localTippingPoints","ev","preventDefault","prevId","currentId","prev","opacity","tipIcon","left","top","SignIn","history","useHistory","logo","LoadingIndicator","loadingMessage","completedMessage","isLoading","showCompletedMessage","timeout","CSSTransition","in","classNames","unmountOnExit","SignUp","setError","isCheckingICForUser","setIsCheckingICForUser","isSigningIn","setIsSigningIn","usernameInputRef","userName","isArray","onSubmit","evt","stopPropagation","htmlFor","placeholder","hidden","Feed","profileInfo","feed","setFeed","setIsLoading","catch","e","rewards","Discover","setVideos","searchTerm","setSearchTerm","videoPreview","setVideoPreview","setLoading","searchedVideos","searchRef","debouncedChangeHandler","handleClick","clickedVideo","onChange","Upload","onUpload","setVideoFile","videoPreviewURL","setVideoPreviewURL","uploading","setUploading","uploadingClean","setUploadingClean","inputRef","textAreaRef","videoUploadController","click","buffer","vidURL","accept","files","item","rows","Rewards","rewardsView","FollowButton","isFollowing","handleFollow","FollowUserRow","following","disableFollow","setIsFollowing","event","Profile","currentUser","onLogOut","useParams","activeSubView","setActiveSubView","goBack","userProfile","setUserProfile","setProfilePic","currentUserFollows","initialIsFollowed","indexOf","isFollowed","setIsFollowed","isCurrentUserProfile","fetchUserProfile","profileData","fetchProfilePic","picData","imgSrc","uploadedVideos","followers","backIcon","fontSize","label","count","index","ProfileNavLink","uploadedVideo","role","DROP_DAY_LS_KEY","DropDayNotification","isVisible","setIsVisible","closeAlert","setItem","pollIsDropDay","result","getItem","err","interval","setInterval","clearInterval","giftIcon","chevron","KEY_LOCALSTORAGE_READ_MESSAGES_TIME","rewardPointsReducer","acc","message","reward","uploadReward","superlikerReward","transferReward","unreadMessagesFilter","lastReadTime","RewardShowerNotification","currentRewards","setRewards","isDismissed","setDismissed","checkForNewMessages","messages","unreadMessages","rewardPoints","reduce","clearMessages","RewardPointAnim","getPathRoot","path","MainNav","paths","setDestination","destination","findIndex","currentIndex","pathname","destinationIndex","getElementById","innerHTML","rewardsIcon","wrapPrivateRouteWithSlide","render","PrivateRoutes","refreshProfileInfo","privateRoutes","params","privatePaths","wrapRouteWithFade","Component","AppRouter","exact","TransitionGroup","CanCanApp","ReactDOM"],"mappings":"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","file":"static/js/main.2a343f97.chunk.js","sourcesContent":["import { useEffect, useState } from \"react\";\nimport {\n createVideo,\n getVideoInfo,\n putVideoChunk,\n putVideoPic,\n} from \"./canister\";\nimport { VideoInfo, VideoInit } from \"./canister/typings\";\nimport { MAX_CHUNK_SIZE, encodeArrayBuffer, hashtagRegExp } from \"./index\";\n\n// Determines number of chunks and creates the VideoInfo\nexport function getVideoInit(\n userId: string,\n file: File,\n caption: string\n): VideoInit {\n const chunkCount = Number(Math.ceil(file.size / MAX_CHUNK_SIZE));\n return {\n caption,\n // @ts-ignore\n chunkCount,\n // @ts-ignore\n createdAt: Number(Date.now() * 1000), // motoko is using nanoseconds\n name: file.name.replace(/\\.mp4/, \"\"),\n tags: caption.match(hashtagRegExp) || [],\n userId,\n };\n}\n\nexport interface UploadVideoInit {\n name: string;\n caption: string;\n chunkCount: number;\n userId: string;\n}\n\n// Divides the file into chunks and uploads them to the canister in sequence\nasync function processAndUploadChunk(\n videoBuffer: ArrayBuffer,\n byteStart: number,\n videoSize: number,\n videoId: string,\n chunk: number\n) {\n const videoSlice = videoBuffer.slice(\n byteStart,\n Math.min(videoSize, byteStart + MAX_CHUNK_SIZE)\n );\n const sliceToNat = encodeArrayBuffer(videoSlice);\n return putVideoChunk(videoId, chunk, sliceToNat);\n}\n\n// Wraps up the previous functions into one step for the UI to trigger\nasync function uploadVideo(userId: string, file: File, caption: string) {\n const videoBuffer = (await file?.arrayBuffer()) || new ArrayBuffer(0);\n\n const videoInit = getVideoInit(userId, file, caption);\n const videoId = await createVideo(videoInit);\n\n let chunk = 1;\n const thumb = await generateThumbnail(file);\n await uploadVideoPic(videoId, thumb);\n\n const putChunkPromises: Promise<[] | [null]>[] = [];\n for (\n let byteStart = 0;\n byteStart < file.size;\n byteStart += MAX_CHUNK_SIZE, chunk++\n ) {\n putChunkPromises.push(\n processAndUploadChunk(videoBuffer, byteStart, file.size, videoId, chunk)\n );\n }\n\n await Promise.all(putChunkPromises);\n\n return await checkVidFromIC(videoId, userId);\n}\n\n// This isn't Internet Computer specific, just a helper to generate an image\n// from a video file\nexport function generateThumbnail(videoFile: File) {\n const videoElement = document.createElement(\"video\");\n const thumbnailCanvas = document.createElement(\"canvas\");\n const canvasContext = thumbnailCanvas.getContext(\"2d\");\n\n const videoUrl = URL.createObjectURL(videoFile);\n videoElement.src = videoUrl;\n\n videoElement.addEventListener(\"loadedmetadata\", () => {\n thumbnailCanvas.width = videoElement.videoWidth;\n thumbnailCanvas.height = videoElement.videoHeight;\n });\n\n return new Promise((resolve, reject) => {\n videoElement.addEventListener(\"timeupdate\", () => {\n canvasContext!.drawImage(\n videoElement,\n 0,\n 0,\n videoElement.videoWidth,\n videoElement.videoHeight\n );\n\n URL.revokeObjectURL(videoUrl);\n\n thumbnailCanvas.toBlob(\n (canvasBlob) => {\n canvasBlob!.arrayBuffer().then((arrayBuffer) => {\n resolve([...new Uint8Array(arrayBuffer)]);\n });\n },\n \"image/jpeg\",\n 0.7\n );\n });\n setTimeout(() => {\n reject(\"took too long to create blob\");\n }, 5000);\n videoElement.currentTime = 0.01;\n });\n}\n\n// Stores the videoPic on the canister\nasync function uploadVideoPic(videoId: string, file: number[]) {\n console.log(\"Storing video thumbnail...\");\n try {\n await putVideoPic(videoId, file);\n console.log(`Video thumbnail stored for ${videoId}`);\n } catch (error) {\n console.error(\"Unable to store video thumbnail:\", error);\n }\n}\n\n// Gets videoInfo from the IC after we've uploaded\nasync function checkVidFromIC(videoId: string, userId: string) {\n console.log(\"Checking canister for uploaded video...\");\n const resultFromCanCan = await getVideoInfo(userId, videoId);\n if (resultFromCanCan === null) {\n throw Error(\"Invalid video received from CanCan Canister\");\n }\n console.log(\"Upload verified.\");\n return resultFromCanCan;\n}\n\n// This hook exposes functions to set video data, trigger the upload, and return\n// with \"success\" to toggle loading states.\nexport function useUploadVideo({ userId }: { userId: string }) {\n const [completedVideo, setCompletedVideo] = useState();\n const [file, setFile] = useState();\n const [caption, setCaption] = useState(\"\");\n const [ready, setReady] = useState(false);\n\n async function handleUpload(fileToUpload) {\n console.info(\"Storing video...\");\n try {\n console.time(\"Stored in\");\n const video = await uploadVideo(userId, fileToUpload, caption);\n\n setCompletedVideo(video);\n setReady(false);\n setFile(undefined);\n console.timeEnd(\"Stored in\");\n } catch (error) {\n console.error(\"Failed to store video.\", error);\n }\n }\n\n useEffect(() => {\n if (ready && file !== undefined) {\n handleUpload(file);\n }\n }, [ready]);\n\n return {\n completedVideo,\n setCaption,\n setFile,\n setReady,\n };\n}\n","import { Identity } from '@dfinity/agent';\nimport { AuthClient } from '@dfinity/auth-client';\n\n// Where the IDP should be servied from\nconst IDENTITY_URL =\n new URLSearchParams(document.location.search).get('internetIdentityUrl') ||\n process.env.REACT_APP_INTERNET_IDENTITY_URL ||\n 'https://identity.ic0.app';\n\n/*\n * A simple wrapper for the official auth client to initialize it and wrap\n * some of the methods in promises\n */\nclass AuthClientWrapper {\n public authClient?: AuthClient;\n public ready = false;\n constructor() {\n return this;\n }\n\n // Create a new auth client and update it's ready state\n async create() {\n this.authClient = await AuthClient.create();\n await this.authClient?.isAuthenticated();\n this.ready = true;\n }\n\n async login(): Promise {\n return new Promise(async (resolve) => {\n await this.authClient?.login({\n identityProvider: IDENTITY_URL,\n onSuccess: async () => {\n resolve(this.authClient?.getIdentity());\n },\n });\n });\n }\n\n async logout() {\n return this.authClient?.logout({ returnTo: '/' });\n }\n\n async getIdentity() {\n return this.authClient?.getIdentity();\n }\n\n async isAuthenticated() {\n return this.authClient?.isAuthenticated();\n }\n}\n\nexport const authClient = new AuthClientWrapper();\n","import React, { createContext, useContext, useEffect, useState } from \"react\";\nimport { authClient as authenticationClient } from \"./authClient\";\nimport {\n getUserFromCanister,\n getUserFromStorage,\n KEY_LOCALSTORAGE_USER,\n} from \"./index\";\n\nimport { actorController } from \"./canister/actor\";\nimport { Identity } from \"@dfinity/agent\";\nimport { ProfileInfoPlus } from \"./canister/typings\";\n\nexport interface AuthContext {\n isAuthenticated: boolean;\n isAuthReady: boolean;\n hasCanCanAccount: boolean;\n identity?: Identity;\n logIn: () => void;\n logOut: () => void;\n user: ProfileInfoPlus | undefined;\n setUser: (p: ProfileInfoPlus | undefined) => void;\n}\n\n// Provider hook that creates auth object and handles state\nexport function useProvideAuth(authClient): AuthContext {\n const [user, setUser] = useState();\n const [isAuthenticatedLocal, setIsAuthenticatedLocal] = useState(\n false\n );\n const [_identity, _setIdentity] = useState();\n const [isAuthClientReady, setAuthClientReady] = useState(false);\n const [urlWithSearch] = useState(globalThis.location.search);\n\n // Creating the auth client is async and no auth related checks can happen\n // until it's ready so we set a state variable to keep track of it\n if (!authClient.ready) {\n authClient.create().then(() => setAuthClientReady(true));\n }\n\n // Use the user from local storage if it is set so the flow doesn't have to\n // make an async query.\n // const setUserFromLocalStorage = () => {\n // const lsUser = getUserFromStorage(localStorage, KEY_LOCALSTORAGE_USER);\n // if (lsUser) {\n // setUser(lsUser);\n // setIsAuthenticatedLocal(true);\n // // Check to make sure your local storage user exists on the backend, and\n // // log out if it doesn't (this is when you have your user stored in local\n // // storage but the user was cleared from the backend)\n // getUserFromCanister(lsUser.userName).then((user_) => !user_ && logOut());\n // return () => void 0;\n // }\n // };\n\n // Once the auth client is initialized, get the identity and check that they\n // are authenticated, then set them to be fully logged in.\n useEffect(() => {\n if (!authClient.ready) return;\n Promise.all([authClient.getIdentity(), authClient.isAuthenticated()]).then(\n ([identity, isAuthenticated]) => {\n setIsAuthenticatedLocal(isAuthenticated || false);\n _setIdentity(identity);\n // if (isAuthenticated) {\n // setUserFromLocalStorage();\n // }\n setAuthClientReady(true);\n }\n );\n }, [isAuthClientReady]);\n\n // For testing environments only, this bypasses the authentication with an\n // identity provider for testing purposes.\n // const DFX_NETWORK = process.env.DFX_NETWORK || \"local\";\n // useEffect(() => {\n // if (DFX_NETWORK === \"local\") {\n // const testUserParam = new URLSearchParams(urlWithSearch).get(\"testUser\");\n // if (testUserParam) {\n // setIsAuthenticatedLocal(true);\n // setAuthClientReady(true);\n // // setUserFromLocalStorage();\n // if (!user) {\n // getUserFromCanister(testUserParam).then(\n // (user_) => !user && user_ && setUser(user_)\n // );\n // }\n // }\n // }\n // }, [urlWithSearch, user]);\n\n // When user is set, and is not in local storage yet store the user object\n // from the canister in local storag so the user doesn't need to be fetched\n // every load. Then insure user is correctly logged in with identity service,\n // and set them to not logged in if not.\n // useEffect(() => {\n // if (user && !getUserFromStorage(localStorage, KEY_LOCALSTORAGE_USER)) {\n // localStorage.setItem(\n // KEY_LOCALSTORAGE_USER,\n // JSON.stringify({ ...user, rewards: user.rewards }, (key, value) =>\n // typeof value === \"bigint\" ? value.toString() : value\n // )\n // );\n // if (!authClient.ready) return;\n // (async () => {\n // const identity = await authClient.getIdentity();\n // if (identity && !identity.getPrincipal().isAnonymous()) {\n // _setIdentity(identity);\n // }\n // })();\n // }\n // }, [user]);\n\n useEffect(() => {\n if (_identity && !_identity.getPrincipal().isAnonymous()) {\n // The auth client isn't ready to make requests until it's completed the\n // async authenticate actor method.\n setAuthClientReady(false);\n actorController.authenticateActor(_identity).then(() => {\n setAuthClientReady(true);\n });\n } else {\n actorController.unauthenticateActor();\n }\n }, [_identity]);\n\n // Just creating variables here so that it's pretty below\n const identity = _identity;\n const isAuthenticated = isAuthenticatedLocal;\n\n // Login to the identity provider by sending user to Internet Identity\n // and logging them in.\n const logIn = async function (): Promise {\n if (!authClient) return;\n await authClient.login();\n const identity = await authClient.getIdentity();\n if (identity) {\n setIsAuthenticatedLocal(true);\n _setIdentity(identity);\n } else {\n console.error(\"Could not get identity from internet identity\");\n }\n };\n\n // Clears the authClient of any cached data, and redirects user to root.\n function logOut() {\n setUser(undefined);\n setIsAuthenticatedLocal(false);\n localStorage.removeItem(KEY_LOCALSTORAGE_USER);\n if (!authClient.ready) return;\n authClient.logout();\n }\n\n return {\n isAuthenticated,\n isAuthReady: isAuthClientReady && actorController.isReady,\n hasCanCanAccount: user !== undefined,\n logIn,\n logOut,\n user,\n identity,\n setUser,\n };\n}\n\nconst authContext = createContext(null!);\n\nexport function ProvideAuth({ children }) {\n const auth = useProvideAuth(authenticationClient);\n return {children};\n}\n\nexport const useAuth = () => {\n return useContext(authContext);\n};\n","// Updated required for \"mobile web app\" behavior\n// https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html\n\nconst APP_TITLE = \"CanCan\";\n\nconst updates = [\n {\n el: \"meta\",\n attrs: { name: \"apple-mobile-web-app-title\", content: APP_TITLE },\n },\n {\n el: \"meta\",\n attrs: { name: \"apple-mobile-web-app-capable\", content: \"yes\" },\n },\n {\n el: \"meta\",\n attrs: {\n name: \"apple-mobile-web-app-status-bar-style\",\n content: \"black\",\n },\n },\n];\n\nexport const updateHead = (document: Document) => {\n document.title = APP_TITLE;\n\n updates.forEach(({ el, attrs }) => {\n const update = document.createElement(el);\n Object.entries(attrs).forEach(([attr, value]) => {\n // @ts-ignore\n update[attr] = value;\n });\n document.head.appendChild(update);\n });\n};\n","import { Principal } from \"@dfinity/agent\";\nimport { Optional } from \"./canister\";\n\nexport * from \"./CatchAll\";\nexport * from \"./video\";\nexport * from \"./auth\";\nexport * from \"./updateHead\";\nexport * from \"./canister\";\n\nexport const KEY_LOCALSTORAGE_USER = `ic-cancan-user`;\n\nexport const MAX_CHUNK_SIZE = 1024 * 500; // 500kb\nexport const REWARDS_CHECK_INTERVAL = 60000;\nexport const hashtagRegExp = /(?:\\s|^)#[A-Za-z0-9\\-._]+(?:\\s|$)/gim;\n\nexport const encodeArrayBuffer = (file: ArrayBuffer): number[] =>\n Array.from(new Uint8Array(file));\n\nexport function unwrap(val: Optional): T | null {\n if (val[0] === undefined) {\n return null;\n } else {\n return val[0];\n }\n}\n\nexport function formatBigNumber(number: number): string {\n if (number >= 1_000_000_000) {\n return `${(number / 1_000_000_000).toFixed(2)}B`;\n }\n if (number >= 1_000_000) {\n return `${(number / 1_000_000).toFixed(2)}M`;\n }\n if (number >= 1_000) {\n return `${(number / 1_000).toFixed(1)}K`;\n }\n return `${number}`;\n}\n\n// Converts a file from a byteArray to a blob URL\n// TODO: Detect mime-type, \"fileToBlobUrl\" https://stackoverflow.com/a/29672957\nexport function fileToImgSrc(file: [] | number[][], imgType = \"jpeg\"): string {\n const byteArray = new Uint8Array(file[0]);\n const picBlob = new Blob([byteArray], { type: `image/${imgType}` });\n const picSrc = URL.createObjectURL(picBlob);\n return picSrc;\n}\n\n// Converts a word into a hex color for placeholder profile pic backgrounds\nexport function textToColor(text: string): string {\n const numStringFromString = text\n .split(\"\")\n .map((char) => char.charCodeAt(0))\n .join(\"\");\n let hexFromNumString = parseInt(numStringFromString, 10).toString(16);\n const hexLength = hexFromNumString.length;\n const trimAmount = hexLength - 6;\n\n if (trimAmount < 0) {\n for (let i = 0; i < Math.abs(trimAmount); i++) {\n hexFromNumString += \"0\";\n }\n }\n if (trimAmount > 1) {\n const startIndex = Math.ceil(trimAmount / 2);\n const hexArray = hexFromNumString.split(\"\");\n const trimmedArray = hexArray.slice(startIndex, startIndex + 6);\n\n hexFromNumString = trimmedArray.join(\"\");\n }\n\n return `#${hexFromNumString}`;\n}\n\n// Regular expressions for detecting canisterId in various formats\nconst ic0AppHostRegEx = /(?:(?.*)\\.)?(?[^.]*)\\.(?ic0\\.app)$/;\nconst localhostRegEx = /(?(?:\\w{5}-){4}cai)\\.[^.]*$/;\n\n// Detect canisterId from current URL\nexport function getCanisterId(): Principal {\n const loc = new URL(window.location.toString());\n const hostName = loc.hostname;\n const matchesIc0 = ic0AppHostRegEx.exec(hostName);\n const matchesLocalhost = localhostRegEx.exec(hostName);\n\n if (matchesIc0?.groups?.canisterId) {\n return Principal.fromText(matchesIc0.groups.canisterId);\n } else if (matchesLocalhost?.groups?.canisterId) {\n return Principal.fromText(matchesLocalhost.groups.canisterId!);\n } else if (loc.searchParams.get(\"canisterId\")) {\n return Principal.fromText(loc.searchParams.get(\"canisterId\")!);\n } else {\n throw new Error(\"Could not find the canister ID.\");\n }\n}\n","/// \n\n/*\n * This file wraps all of our canister interaction functions and makes sure they\n * return the expected values by massaging any data necessary.\n */\n\nimport { Principal } from \"@dfinity/agent\";\n\nimport {\n Message,\n ProfileInfoPlus,\n VideoInfo,\n VideoInit,\n VideoResults,\n} from \"./canister/typings\";\nimport { unwrap } from \"./index\";\nimport { actorController } from \"./canister/actor\";\n\nconst CanCan = actorController;\n\nexport type Optional = [Type] | [];\n\nexport function getUserFromStorage(\n storage = window.localStorage,\n key: string\n): ProfileInfoPlus | undefined {\n const lsUser = storage.getItem(key);\n if (lsUser) {\n return JSON.parse(lsUser, (k, v) => {\n if (k === \"rewards\") {\n return BigInt(v);\n }\n return v;\n }) as ProfileInfoPlus;\n } else {\n return undefined;\n }\n}\n\nexport async function getUserNameByPrincipal(principal: Principal) {\n const icUserName = unwrap(\n await CanCan.actor.getUserNameByPrincipal(principal)\n )!;\n return icUserName;\n}\n\nexport async function createUser(\n userId: string,\n principal?: Principal | null\n): Promise {\n if (!principal) {\n throw Error(\"trying to create user without principal\");\n }\n const profile = unwrap(\n await CanCan.actor.createProfile(userId, [])\n );\n if (profile) {\n return profile;\n } else {\n throw Error(\"failed to create profile: \" + JSON.stringify(profile));\n }\n}\n\nexport async function findOrCreateUser(\n userId: string,\n principal: Principal,\n key: string\n): Promise {\n const lsUSER = getUserFromStorage(undefined, key);\n if (lsUSER !== undefined) {\n return lsUSER;\n }\n\n const icUser = await getUserFromCanister(userId);\n if (icUser !== null) {\n return icUser;\n } else {\n try {\n createUser(userId, principal);\n } catch (error) {\n return Promise.reject(error);\n }\n throw Error(\"couldnt find or create user\");\n }\n}\n\nexport async function isDropDay(): Promise {\n return Boolean(unwrap(await CanCan.actor.isDropDay()));\n}\n\nexport async function getUserFromCanister(\n userId: string\n): Promise {\n const icUser = unwrap(\n await CanCan.actor.getProfilePlus([userId], userId)\n );\n if (icUser) {\n return icUser;\n } else {\n return null;\n }\n}\n\nexport async function getSearchVideos(\n userId: string,\n terms: string[],\n limit: [] | [number] = [3]\n): Promise {\n // @ts-ignore\n const videos = unwrap(\n await CanCan.actor.getSearchVideos(userId, terms, limit)\n );\n if (videos !== null) {\n const unwrappedVideos = videos.map((v) => v[0]);\n return unwrappedVideos;\n } else {\n return Promise.resolve([]);\n }\n}\n\nexport async function getFeedVideos(userId: string): Promise {\n const videos = unwrap(\n await CanCan.actor.getFeedVideos(userId, [])\n );\n if (videos !== null) {\n const unwrappedVideos = videos.map((v) => v[0]);\n return unwrappedVideos;\n } else {\n return Promise.resolve([]);\n }\n}\n\nexport async function getVideoInfo(userId: string, videoId: string) {\n const videoInfo = unwrap(await CanCan.actor.getVideoInfo([userId], videoId));\n if (videoInfo !== null) {\n return videoInfo;\n } else {\n throw Error(\"no video found with id: \" + videoId);\n }\n}\nexport async function getProfilePic(userId: string) {\n const profilePic = unwrap(await CanCan.actor.getProfilePic(userId));\n return profilePic;\n}\n\nexport async function createVideo(videoInit: VideoInit): Promise {\n const videoId = unwrap(await CanCan.actor.createVideo(videoInit));\n if (videoId) {\n return videoId;\n } else {\n throw Error(\"failed to create video\");\n }\n}\n\nexport async function follow(\n userToFollow: string,\n follower: string,\n willFollow: boolean\n) {\n try {\n await CanCan.actor.putProfileFollow(userToFollow, follower, willFollow);\n } catch (error) {\n console.error(error);\n }\n}\n\nexport async function like(user: string, videoId: string, willLike: boolean) {\n try {\n await CanCan.actor.putProfileVideoLike(user, videoId, willLike);\n } catch (error) {\n console.error(error);\n }\n}\n\nexport async function superLike(\n user: string,\n videoId: string,\n willSuperLike: boolean\n) {\n try {\n await CanCan.actor.putSuperLike(user, videoId, willSuperLike);\n } catch (error) {\n console.error(error);\n }\n}\n\n// Videos are stored as chunked byteArrays, and must be assembled once received\nexport async function getVideoChunks(videoInfo: VideoInfo): Promise {\n const { videoId, chunkCount } = videoInfo;\n const chunkBuffers: Buffer[] = [];\n const chunksAsPromises: Array>> = [];\n for (let i = 1; i <= Number(chunkCount.toString()); i++) {\n chunksAsPromises.push(CanCan.actor.getVideoChunk(videoId, i));\n }\n const nestedBytes: number[][] = (await Promise.all(chunksAsPromises))\n .map(unwrap)\n .filter((v): v is number[] => v !== null);\n nestedBytes.forEach((bytes) => {\n const bytesAsBuffer = Buffer.from(new Uint8Array(bytes));\n chunkBuffers.push(bytesAsBuffer);\n });\n const videoBlob = new Blob([Buffer.concat(chunkBuffers)], {\n type: \"video/mp4\",\n });\n const vidURL = URL.createObjectURL(videoBlob);\n return vidURL;\n}\n\nexport async function putVideoChunk(\n videoId: string,\n chunkNum: number,\n chunkData: number[]\n) {\n return CanCan.actor.putVideoChunk(videoId, chunkNum, chunkData);\n}\n\nexport async function putVideoPic(videoId: string, file: number[]) {\n return CanCan.actor.putVideoPic(videoId, [file]);\n}\n\nexport async function getVideoPic(videoId: string): Promise {\n const icResponse = await CanCan.actor.getVideoPic(videoId);\n const pic = unwrap(icResponse);\n if (pic !== null) {\n return pic;\n } else {\n throw Error(\"pic should not be empty\");\n }\n}\n\nexport function getLocationCanisterPrincipal(location: Location): Principal {\n const pattern = /(\\.?((?:[a-z0-9]{5}-){4}[a-z0-9]{3})\\..*)|(canisterId=([^$&]+))/;\n const match = location.href.match(pattern);\n if (!match) {\n throw new Error(\"Failed to parse url containing canisterId\");\n }\n const [, , canisterId] = match;\n const canisterPrincipal = Principal.fromText(canisterId);\n return canisterPrincipal;\n}\n\nexport async function checkUsername(username: string): Promise {\n return await CanCan.actor.checkUsernameAvailable(username);\n}\n\nexport async function getMessages(username: string): Promise {\n const messages = await CanCan.actor.getMessages(username);\n return messages;\n}\n\nexport async function putRewardTransfer(\n sender: string,\n recipient: string,\n amount: BigInt\n) {\n return await CanCan.actor.putRewardTransfer(sender, recipient, amount);\n}\n\nexport async function putAbuseFlagVideo(\n reporter: string,\n target: string,\n shouldFlag: boolean\n) {\n return await CanCan.actor.putAbuseFlagVideo(reporter, target, shouldFlag);\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { Link } from \"react-router-dom\";\n\nimport FlagButton from \"./FlagButton\";\nimport SuperLikeButton from \"./SuperLikeButton\";\nimport TippingButton from \"./TippingButton\";\nimport { ProfilePic } from \"./ProfilePic\";\nimport { SuperLikeEffect } from \"./SuperLikeEffect\";\nimport { getVideoChunks, getProfilePic, like, superLike } from \"../utils\";\nimport likeIcon from \"../assets/images/icon-like.png\";\nimport commentIcon from \"../assets/images/icon-comment.png\";\nimport shareIcon from \"../assets/images/icon-share.png\";\nimport \"./Video.scss\";\n\n// The amount of flags a video needs before we blur it out on frontend\nconst VIDEO_BLUR_MIN = 1;\n\ninterface VideoProps {\n videoInfo: any;\n userId: string;\n userRewardPoints: number;\n onRefreshUser?: any;\n isPreview?: boolean;\n onClose?: () => void;\n}\n\n// Wrapper to allow us to use the same video component for single previews from\n// Profile and Discover, and for all videos in the Feed\nexport function Video(props: VideoProps) {\n const {\n isPreview = false,\n userId,\n userRewardPoints,\n onRefreshUser,\n videoInfo,\n onClose = () => {},\n } = props;\n return isPreview ? (\n
\n \n
\n ) : (\n \n );\n}\n\nfunction VideoBase(props: VideoProps) {\n const {\n videoInfo,\n userId,\n userRewardPoints = 0,\n isPreview = false,\n onRefreshUser = () => {},\n onClose = () => {},\n } = props;\n const [play, setPlay] = useState(false);\n const [videoSourceURL, setVideoSourceURL] = useState();\n const [userPic, setUserPic] = useState();\n const [userLikes, setUserLikes] = useState(videoInfo.likes.includes(userId));\n const [isSuperLiked, setIsSuperLiked] = useState(\n videoInfo.superLikes.includes(userId)\n );\n\n const videoIsFlagged = videoInfo.abuseFlagCount >= VIDEO_BLUR_MIN;\n\n const videoRef = useRef(null);\n\n const handlePlayClick = function () {\n setPlay(!play);\n };\n\n // Load video and uploader profilePic on first mount.\n useEffect(() => {\n if (!videoInfo) {\n return;\n }\n getVideoChunks(videoInfo).then((blobURL) => {\n setVideoSourceURL(blobURL);\n setPlay(true);\n });\n getProfilePic(videoInfo.userId).then((bytes) => {\n if (!bytes) {\n return;\n }\n const picBlob = new Blob([Buffer.from(new Uint8Array(bytes))], {\n type: \"image/jpeg\",\n });\n const pic = URL.createObjectURL(picBlob);\n setUserPic(pic);\n });\n\n return () => videoRef.current?.pause();\n }, [videoInfo?.videoId]);\n\n // Only play video if it has not been flagged/reported\n useEffect(() => {\n if (!videoIsFlagged) {\n play ? videoRef.current?.play() : videoRef.current?.pause();\n }\n }, [play]);\n\n function handleLike() {\n like(userId, videoInfo.videoId, !userLikes);\n setUserLikes((state) => !state);\n }\n\n function handleSuperLike() {\n if (!isSuperLiked) {\n setIsSuperLiked(true);\n superLike(userId, videoInfo.videoId, true);\n }\n }\n\n const isCurrentUser = userId === videoInfo.userId;\n const videoBlurStyle = videoIsFlagged ? { filter: \"blur(20px)\" } : {};\n\n return (\n
\n \n {isPreview && (\n \n )}\n \n
\n \n
\n
\n \n \n @{videoInfo.userId}\n \n \n

{videoInfo.caption}

\n
\n
\n
\n\n {/* Side controls for user interaction with the video. */}\n
\n
\n \n \n {/*currentUser?.remainingSuperlikes ||*/ 0}/\n {/*currentUser?.totalSuperlikes ||*/ 10}\n \n
\n
\n \n
\n
\n \n \n {videoInfo.likes.length +\n // if they are toggling on and off, only subtract if they are\n // already a liker it and only add if they are not already a liker\n (userLikes\n ? videoInfo.likes.includes(userId)\n ? 0\n : 1\n : videoInfo.likes.includes(userId)\n ? -1\n : 0)}\n \n
\n
\n comment.userId === userId)\n ? \"active\"\n : \"\"\n }\n alt=\"icon: comment on current video\"\n />\n {videoInfo.comments?.length ?? 0}\n
\n
\n \n {videoInfo.shares?.length ?? 0}\n
\n
\n \n
\n
\n
\n );\n}\n","import React from \"react\";\nimport { textToColor } from \"../utils\";\n\nexport function ProfilePic({ name, profilePic }) {\n const profileColor = textToColor(name);\n\n return (\n
\n {profilePic ? (\n {name}\n ) : (\n \n \n \n \n \n \n
\n )}\n \n );\n}\n","export default ({ IDL }) => {\n const ProfilePic_2 = IDL.Vec(IDL.Nat8);\n const ProfilePic = ProfilePic_2;\n const VideoPic_2 = IDL.Vec(IDL.Nat8);\n const Timestamp = IDL.Int;\n const UserId = IDL.Text;\n const VideoId_2 = IDL.Text;\n const VideoInfo_2 = IDL.Record({\n 'pic' : IDL.Opt(VideoPic_2),\n 'viralAt' : IDL.Opt(Timestamp),\n 'userId' : UserId,\n 'name' : IDL.Text,\n 'createdAt' : Timestamp,\n 'tags' : IDL.Vec(IDL.Text),\n 'likes' : IDL.Vec(UserId),\n 'viewCount' : IDL.Nat,\n 'caption' : IDL.Text,\n 'chunkCount' : IDL.Nat,\n 'superLikes' : IDL.Vec(UserId),\n 'viewerHasFlagged' : IDL.Opt(IDL.Bool),\n 'abuseFlagCount' : IDL.Nat,\n 'uploadedAt' : Timestamp,\n 'videoId' : VideoId_2,\n });\n const AllowanceBalance = IDL.Variant({\n 'zeroUntil' : Timestamp,\n 'zeroForever' : IDL.Null,\n 'nonZero' : IDL.Nat,\n });\n const UserAllowances = IDL.Record({\n 'abuseFlags' : AllowanceBalance,\n 'superLikes' : AllowanceBalance,\n });\n const ProfileInfo_2 = IDL.Record({\n 'userName' : IDL.Text,\n 'uploadedVideos' : IDL.Vec(VideoId_2),\n 'likedVideos' : IDL.Vec(VideoId_2),\n 'rewards' : IDL.Nat,\n 'hasPic' : IDL.Bool,\n 'followers' : IDL.Vec(UserId),\n 'following' : IDL.Vec(UserId),\n 'abuseFlagCount' : IDL.Nat,\n });\n const ProfileInfoPlus_2 = IDL.Record({\n 'userName' : IDL.Text,\n 'uploadedVideos' : IDL.Vec(VideoInfo_2),\n 'likedVideos' : IDL.Vec(VideoInfo_2),\n 'rewards' : IDL.Nat,\n 'allowances' : IDL.Opt(UserAllowances),\n 'hasPic' : IDL.Bool,\n 'followers' : IDL.Vec(ProfileInfo_2),\n 'following' : IDL.Vec(ProfileInfo_2),\n 'viewerHasFlagged' : IDL.Opt(IDL.Bool),\n 'abuseFlagCount' : IDL.Nat,\n });\n const ProfileInfoPlus = ProfileInfoPlus_2;\n const UserId_2 = UserId;\n const VideoId = VideoId_2;\n const VideoInit_2 = IDL.Record({\n 'userId' : UserId,\n 'name' : IDL.Text,\n 'createdAt' : Timestamp,\n 'tags' : IDL.Vec(IDL.Text),\n 'caption' : IDL.Text,\n 'chunkCount' : IDL.Nat,\n });\n const VideoInit = VideoInit_2;\n const VideoId_3 = VideoId_2;\n const UserId_3 = UserId;\n const VideosPred = IDL.Variant({\n 'containsAll' : IDL.Vec(VideoId_3),\n 'equals' : IDL.Vec(VideoId_3),\n });\n const TimeMode = IDL.Variant({ 'ic' : IDL.Null, 'script' : IDL.Int });\n const Command = IDL.Variant({\n 'assertVideoVirality' : IDL.Record({\n 'isViral' : IDL.Bool,\n 'videoId' : VideoId_3,\n }),\n 'putProfileFollow' : IDL.Record({\n 'toFollow' : UserId_3,\n 'userId' : UserId_3,\n 'follows' : IDL.Bool,\n }),\n 'createTestData' : IDL.Record({\n 'users' : IDL.Vec(UserId_3),\n 'videos' : IDL.Vec(IDL.Tuple(UserId_3, VideoId_3)),\n }),\n 'putSuperLike' : IDL.Record({\n 'userId' : UserId_3,\n 'superLikes' : IDL.Bool,\n 'videoId' : VideoId_3,\n }),\n 'assertVideoFeed' : IDL.Record({\n 'userId' : UserId_3,\n 'limit' : IDL.Opt(IDL.Nat),\n 'videosPred' : VideosPred,\n }),\n 'putRewardTransfer' : IDL.Record({\n 'sender' : UserId_3,\n 'amount' : IDL.Nat,\n 'receiver' : UserId_3,\n }),\n 'reset' : TimeMode,\n });\n const Result = IDL.Variant({ 'ok' : IDL.Null, 'err' : IDL.Text });\n const TraceCommand = IDL.Record({ 'result' : Result, 'command' : Command });\n const Trace = IDL.Record({\n 'status' : IDL.Variant({ 'ok' : IDL.Null, 'err' : IDL.Null }),\n 'trace' : IDL.Vec(TraceCommand),\n });\n const UserAction = IDL.Variant({\n 'admin' : IDL.Null,\n 'view' : IDL.Null,\n 'create' : IDL.Null,\n 'update' : IDL.Null,\n });\n const ActionTarget = IDL.Variant({\n 'all' : IDL.Null,\n 'video' : VideoId_2,\n 'user' : UserId,\n 'pubView' : IDL.Null,\n });\n const Check = IDL.Record({\n 'userAction' : UserAction,\n 'caller' : IDL.Principal,\n 'actionTarget' : ActionTarget,\n });\n const Event_3 = IDL.Record({\n 'check' : Check,\n 'isOk' : IDL.Bool,\n 'time' : IDL.Int,\n });\n const LikeVideo = IDL.Record({\n 'source' : UserId,\n 'likes' : IDL.Bool,\n 'target' : VideoId_2,\n });\n const AbuseFlag = IDL.Record({\n 'flag' : IDL.Bool,\n 'target' : IDL.Variant({ 'video' : VideoId_2, 'user' : UserId }),\n 'reporter' : UserId,\n });\n const SuperLikeVideoFail = IDL.Record({\n 'source' : UserId,\n 'target' : VideoId_2,\n });\n const SuperLikeVideo = IDL.Record({\n 'source' : UserId,\n 'target' : VideoId_2,\n 'superLikes' : IDL.Bool,\n });\n const RewardPointTransfer = IDL.Record({\n 'sender' : UserId,\n 'amount' : IDL.Nat,\n 'receiver' : UserId,\n });\n const CreateVideo = IDL.Record({ 'info' : VideoInit_2 });\n const CreateProfile = IDL.Record({\n 'pic' : IDL.Opt(ProfilePic_2),\n 'userName' : IDL.Text,\n });\n const ViralVideoSuperLiker = IDL.Record({\n 'time' : IDL.Int,\n 'user' : UserId,\n });\n const ViralVideo = IDL.Record({\n 'video' : VideoId_2,\n 'superLikers' : IDL.Vec(ViralVideoSuperLiker),\n 'uploader' : UserId,\n });\n const Signal = IDL.Variant({ 'viralVideo' : ViralVideo });\n const EventKind = IDL.Variant({\n 'likeVideo' : LikeVideo,\n 'abuseFlag' : AbuseFlag,\n 'superLikeVideoFail' : SuperLikeVideoFail,\n 'superLikeVideo' : SuperLikeVideo,\n 'rewardPointTransfer' : RewardPointTransfer,\n 'createVideo' : CreateVideo,\n 'createProfile' : CreateProfile,\n 'emitSignal' : Signal,\n 'reset' : TimeMode,\n });\n const Event_2 = IDL.Record({\n 'id' : IDL.Nat,\n 'kind' : EventKind,\n 'time' : IDL.Int,\n });\n const VideoResult = IDL.Tuple(VideoInfo_2, IDL.Opt(VideoPic_2));\n const VideoResults_2 = IDL.Vec(VideoResult);\n const VideoResults = VideoResults_2;\n const Event = IDL.Variant({\n 'uploadReward' : IDL.Record({ 'rewards' : IDL.Nat, 'videoId' : VideoId_2 }),\n 'superlikerReward' : IDL.Record({\n 'rewards' : IDL.Nat,\n 'videoId' : VideoId_2,\n }),\n 'transferReward' : IDL.Record({ 'rewards' : IDL.Nat }),\n });\n const Message = IDL.Record({\n 'id' : IDL.Nat,\n 'time' : Timestamp,\n 'event' : Event,\n });\n const ProfileInfo = ProfileInfo_2;\n const VideoInfo = VideoInfo_2;\n const VideoPic = VideoPic_2;\n const CanCan = IDL.Service({\n 'checkUsernameAvailable' : IDL.Func([IDL.Text], [IDL.Bool], ['query']),\n 'createProfile' : IDL.Func(\n [IDL.Text, IDL.Opt(ProfilePic)],\n [IDL.Opt(ProfileInfoPlus)],\n [],\n ),\n 'createTestData' : IDL.Func(\n [IDL.Vec(UserId_2), IDL.Vec(IDL.Tuple(UserId_2, VideoId))],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'createVideo' : IDL.Func([VideoInit], [IDL.Opt(VideoId)], []),\n 'doDemo' : IDL.Func([IDL.Vec(Command)], [IDL.Opt(Trace)], []),\n 'getAccessLog' : IDL.Func([], [IDL.Opt(IDL.Vec(Event_3))], ['query']),\n 'getEventLog' : IDL.Func([], [IDL.Opt(IDL.Vec(Event_2))], ['query']),\n 'getFeedVideos' : IDL.Func(\n [UserId_2, IDL.Opt(IDL.Nat)],\n [IDL.Opt(VideoResults)],\n ['query'],\n ),\n 'getIsSuperLiker' : IDL.Func(\n [UserId_2, VideoId],\n [IDL.Opt(IDL.Bool)],\n ['query'],\n ),\n 'getMessages' : IDL.Func(\n [UserId_2],\n [IDL.Opt(IDL.Vec(Message))],\n ['query'],\n ),\n 'getProfileInfo' : IDL.Func([UserId_2], [IDL.Opt(ProfileInfo)], ['query']),\n 'getProfilePic' : IDL.Func([UserId_2], [IDL.Opt(ProfilePic)], ['query']),\n 'getProfilePlus' : IDL.Func(\n [IDL.Opt(UserId_2), UserId_2],\n [IDL.Opt(ProfileInfoPlus)],\n ['query'],\n ),\n 'getProfileVideos' : IDL.Func(\n [UserId_2, IDL.Opt(IDL.Nat)],\n [IDL.Opt(VideoResults)],\n ['query'],\n ),\n 'getProfiles' : IDL.Func([], [IDL.Opt(IDL.Vec(ProfileInfo))], ['query']),\n 'getSearchVideos' : IDL.Func(\n [UserId_2, IDL.Vec(IDL.Text), IDL.Opt(IDL.Nat)],\n [IDL.Opt(VideoResults)],\n ['query'],\n ),\n 'getSuperLikeValidNow' : IDL.Func(\n [UserId_2, VideoId],\n [IDL.Opt(IDL.Bool)],\n ['query'],\n ),\n 'getUserNameByPrincipal' : IDL.Func(\n [IDL.Principal],\n [IDL.Opt(IDL.Vec(IDL.Text))],\n [],\n ),\n 'getVideoChunk' : IDL.Func(\n [VideoId, IDL.Nat],\n [IDL.Opt(IDL.Vec(IDL.Nat8))],\n ['query'],\n ),\n 'getVideoInfo' : IDL.Func(\n [IDL.Opt(UserId_2), VideoId],\n [IDL.Opt(VideoInfo)],\n ['query'],\n ),\n 'getVideoPic' : IDL.Func([VideoId], [IDL.Opt(VideoPic)], ['query']),\n 'getVideos' : IDL.Func([], [IDL.Opt(IDL.Vec(VideoInfo))], ['query']),\n 'isDropDay' : IDL.Func([], [IDL.Opt(IDL.Bool)], ['query']),\n 'putAbuseFlagUser' : IDL.Func(\n [UserId_2, UserId_2, IDL.Bool],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putAbuseFlagVideo' : IDL.Func(\n [UserId_2, VideoId, IDL.Bool],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putProfileFollow' : IDL.Func(\n [UserId_2, UserId_2, IDL.Bool],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putProfilePic' : IDL.Func(\n [UserId_2, IDL.Opt(ProfilePic)],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putProfileVideoLike' : IDL.Func(\n [UserId_2, VideoId, IDL.Bool],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putRewardTransfer' : IDL.Func(\n [UserId_2, UserId_2, IDL.Nat],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putRewards' : IDL.Func([UserId_2, IDL.Nat], [IDL.Opt(IDL.Null)], []),\n 'putSuperLike' : IDL.Func(\n [UserId_2, VideoId, IDL.Bool],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putTestFollows' : IDL.Func(\n [IDL.Vec(IDL.Tuple(UserId_2, UserId_2))],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putVideoChunk' : IDL.Func(\n [VideoId, IDL.Nat, IDL.Vec(IDL.Nat8)],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'putVideoInfo' : IDL.Func([VideoId, VideoInit], [IDL.Opt(IDL.Null)], []),\n 'putVideoPic' : IDL.Func(\n [VideoId, IDL.Opt(VideoPic)],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'reset' : IDL.Func(\n [IDL.Variant({ 'ic' : IDL.Null, 'script' : IDL.Int })],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n 'scriptTimeTick' : IDL.Func([], [IDL.Opt(IDL.Null)], []),\n 'setTimeMode' : IDL.Func(\n [IDL.Variant({ 'ic' : IDL.Null, 'script' : IDL.Int })],\n [IDL.Opt(IDL.Null)],\n [],\n ),\n });\n return CanCan;\n};\nexport const init = ({ IDL }) => { return []; };","import idlImport from './CanCan.did.js';\nexport const idlFactory = idlImport;\nexport const canisterId = \"r3ysn-mqaaa-aaaah-qabra-cai\";\n","import { Actor, HttpAgent, Identity } from \"@dfinity/agent\";\nimport {\n idlFactory as CanCan_idl,\n canisterId as CanCan_canister_id,\n} from \"dfx-generated/CanCan\";\nimport _SERVICE from \"./typings\";\n\nimport dfxConfig from \"../../../dfx.json\";\n\nconst DFX_NETWORK = process.env.DFX_NETWORK || \"local\";\nconst isLocalEnv = DFX_NETWORK === \"local\";\n\nfunction getHost() {\n // Setting host to undefined will default to the window location 👍🏻\n // return isLocalEnv ? dfxConfig.networks.local.bind : undefined;\n return \"3ysn-mqaaa-aaaah-qabra-cai.raw.ic0.app\"\n}\n\nconst host = getHost();\n\nfunction createActor(identity?: Identity) {\n const agent = new HttpAgent({ host, identity });\n const actor = Actor.createActor<_SERVICE>(CanCan_idl, {\n agent,\n canisterId: CanCan_canister_id,\n });\n return { actor, agent };\n}\n\n/*\n * Responsible for keeping track of the actor, whether the user has logged\n * in again or not. A logged in user uses a different actor with their\n * Identity, to ensure their Principal is passed to the backend.\n */\nclass ActorController {\n _actor: _SERVICE;\n _isAuthenticated: boolean = false;\n isReady: boolean = false;\n\n constructor() {\n this._actor = this.initBaseActor();\n }\n\n initBaseActor() {\n const { agent, actor } = createActor();\n // The root key only has to be fetched for local development environments\n if (isLocalEnv) {\n agent.fetchRootKey().then(() => (this.isReady = true));\n }\n return actor;\n }\n\n /*\n * Get the actor instance to run commands on the canister.\n */\n get actor() {\n return this._actor;\n }\n\n /*\n * Once a user has authenticated and has an identity pass this identity\n * to create a new actor with it, so they pass their Principal to the backend.\n */\n async authenticateActor(identity: Identity) {\n const { agent, actor } = createActor(identity);\n if (isLocalEnv) {\n await agent.fetchRootKey();\n }\n this._actor = actor;\n this._isAuthenticated = true;\n this.isReady = true;\n }\n\n /*\n * If a user unauthenticates, recreate the actor without an identity.\n */\n unauthenticateActor() {\n this._actor = this.initBaseActor();\n }\n}\n\nexport const actorController = new ActorController();\n","import React from \"react\";\nimport Lottie from \"react-lottie-player\";\n\ninterface LottieAnimationProps {\n animation: any;\n height?: number;\n}\n\n/*\n * Wrapper for animations exported from AfterEffects.\n */\nexport default function LottieAnimation({\n animation,\n height,\n}: LottieAnimationProps) {\n return ;\n}\n","import React, { useEffect, useState } from \"react\";\nimport { VideoInfo } from \"../utils/canister/typings\";\nimport { getVideoPic } from \"../utils\";\n\ninterface VideoProps {\n video: VideoInfo;\n onClick: (v: VideoInfo) => void;\n}\n\n/*\n * This represents a single search result or categorized item in the Discover\n * view. It is a clickable image that launches a video preview overlay.\n */\nexport function SearchVideoItem(props: VideoProps): JSX.Element {\n const { video, onClick } = props;\n const [pic, setPic] = useState();\n\n // Since the frontend sends the videoPic to the canister as a byteArray, we\n // have to make sure to translate it back to JPEG before setting it in the DOM\n useEffect(() => {\n getVideoPic(video.videoId).then((picAsNum) => {\n const bufferBlob = [Buffer.from(new Uint8Array(picAsNum))];\n const picBlob = new Blob(bufferBlob, { type: \"image/jpeg\" });\n const pic = URL.createObjectURL(picBlob);\n setPic(pic);\n });\n }, [video.videoId]);\n\n return (\n onClick(video)}\n src={pic}\n />\n );\n}\n","import React, { useEffect, useState } from \"react\";\nimport LottieAnimation from \"./LottieAnimation\";\nimport SuperLikeAnim from \"../assets/animations/Superlike-single.json\";\nimport SuperLikeAnimIcon from \"../assets/animations/Superlike-icon.json\";\nimport \"./SuperLikeEffect.scss\";\n\n/*\n * This uses the wrapped Lottie animation component to display the effect\n */\nexport function SuperLikeEffect({ isActive = false }) {\n const [mainAnimActive, setMainAnimActive] = useState(isActive);\n const [secondAnimActive, setSecondAnimActive] = useState(false);\n\n useEffect(() => {\n const timeoutMain = setTimeout(() => {\n setMainAnimActive(false);\n if (isActive) {\n setSecondAnimActive(true);\n }\n }, 1000);\n const timeoutSecondary = setTimeout(() => {\n setSecondAnimActive(false);\n }, 1500);\n\n if (isActive) {\n setMainAnimActive(true);\n }\n\n return () => {\n clearTimeout(timeoutMain);\n clearTimeout(timeoutSecondary);\n };\n }, [isActive]);\n\n const iconPositionInAnimation = 766;\n let animationPosition = {\n x: -175,\n y: window.innerHeight / 2 - iconPositionInAnimation / 2,\n };\n if (secondAnimActive) {\n animationPosition = {\n x: 0,\n y: window.innerHeight - iconPositionInAnimation,\n };\n }\n\n const animationStyling = {\n transform: `translate(${animationPosition.x}px, ${animationPosition.y}px)`,\n };\n\n return (\n
\n {mainAnimActive && (\n \n )}\n
\n {secondAnimActive && (\n \n )}\n
\n
\n );\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAqCAYAAADI3bkcAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJ6SURBVHgB1ZnRkdowEIZ/ieE5ZmjAVJDrIFBBchUAFeSo4K4EroKQCphUcHRwdBDnHQa/M0B2HckRPtsnWzJnfzMag21WP+tdaSULWHA4HAI6jKkF6lRMbTsYDCLUwMWeKLu42+1mvV5vqoznsaG2oo5+wk7omA6PLvZEgeGQDj9KDGdZUVtQR3GBvUDZ+wY7ImqTPI+LHON3dHjB/8dly1Z1EuOtWLZ3h2rEyt7WPCkzxkPUEwslaJ09eT6fl6guFkrDi3JgSirY8EQdsZox2ZnqL5wDUsop6sNa1kpbgulhToYQ7jzpD5Swj3AnpKf0oL8kMaxC4Tf8MTmdTgEJXsMPHM8jzo/Ew/QPZvDLVAhhOyLYEGgvJ4Ipzr7CL2Oy+Rke0RpFA+HQJANJsVZnyPkQKCe+SIq1EB3heDyOOIZdxt1bE7LgEB2BEu+TRMdgwRE6Ao3Ff+TlconQEfr9/qtQhcUB3WAkVf26QftJllC6lviFlkOTBtfVabXGYcHTc1vH5Ii8O+IPiYc5LMjLz2gv6aI0XdMpL7+ifRNJ6l0mnThU8s3RPq40Xc10JHrTstB4Zk3mibxlft1luW+uQkHzppZQoXGPj52yI2qTvAuFW1UOGyqu5G6gaAqrNfWDBW7PokgsU7oZyJCnZ/i3L3YL5iR2VXbDu4KZG4l+VyxjJZhpWLSVWMZaMNNAIpYmWB6VBDPGDmcINyIU7AGXUXlNpzrgMdLaKznoveQIFansYZP9fr+klex3VIOn2wfUxGnVPBwOuWMeq2OL25PiykUs4+RhjUVccwjc133r1Bgk/InaJdOW8IgXD5sY3mbm2fKwtZjvJXzyFzRi91VMwTQuAAAAAElFTkSuQmCC\"","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAF1SURBVHgB7ZjhTYNAGIa/A36jhAVwAtsJpBMYJ7AbSDfQDXCDdgJHsBvICGyA/gfq+ykYQpB89kDuxz3Jl0u5S/v07r2QO0UNRVFconlAbVERLUPW1FMQBDk/UPQtt0LzsqBYnxx1B8lMQS7Ch1cyR64lR62duq4fyTw5JoJb4oBrMhS43fMSn8hgHDIcK6iLFdTFCupiBXWxgrpYQV2soC5WUBcWfCeDYcGMzOXIggcyFNd19w4Ox3sc70yUTH3fP3xtkjAMt5B8puU5NZVi4nb8QHV7+ZYBZ9Hbsiyv0F4MfEFM8kN+e88iEsMEfXiel/NqQu5n4yr6A/gDb2hWgqEcmaT7Q+ciFmxuvwrB0B3EUpoITzqwqqoYu2psCM8W30gdaULEbxKlVDzSzVlbTy3HiAWxaW5+6eK8bdoLx6kRZXAkf5PmbQhRBgfyN0vehhAtcS9/s+VtCJFgJ3+z5u0sOH98yYlKaAEkGeQ3x+a/lrTPJ8JMcLF1VdmaAAAAAElFTkSuQmCC\"","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAkCAYAAADPRbkKAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAIgSURBVHgB1ZjtUcJAEIZfA78ZGRo4K5ASQgViBUIFQgVgBWAFYAXSAbEC6MD4HwYKYNBdcsFAvj/IXZ6ZnQlJuLzv3t1uJoBidrvdiOIeGTGgHpNimdWEDgaYNhwTAinRxQCTyYROBhiBlCZ0M8AIpDChowFGIKEJXQ0wgmJFJtpRN9WhAFkyBZyNG1U++RrPRKfZbK6DbrjDjZEZbB+Px7ZhGI+IFx3EnqJPJhbXFwo3INftE0UX2cSGUqvVeo1G48N7rhADckm8wBFt4obQTA5brdbU/Z3LgBT+SjFAgZlOwJiW0xsfZDKgULiXk4nUBjabTZfW4gzqhHsZp+oDlPkJif+EHuKZu0QzICsLZ92EPnBZnccakOKXcBqPLpzE80GkAQ3F+xpaqIGU4nngBdXoH+q2Nh2v5TkX4R5wNz4cDg+yKwskTw6P53uliDKwgtNJw7AovijmNKiNjNBzOElmzG2B4pl6yKATBIvngd6RU3RKbDji7aCLPgNU53twGtQ1Fpz1Z6M8bESIZ3wGqM6PAu4b0iBTlIuNGPHMhQGZfeE5xUvmmQaxUC42EohnLjrxVfZVieeN2km6VM8zQBvXxH/2Q3f9jXHF75P+wTsD3uz3FYi3kFL8GW5aFL8yxigR7gMUc+Rhu91OpfgZSoae2UNeZBa+s3ybVI5n+QxQRbj2y/eeSmJQ7edPIENUFdrA1Vw6EnotN8qu94XyB8pr8BdIgJLiAAAAAElFTkSuQmCC\"","import React, { useState } from \"react\";\n\nimport { putAbuseFlagVideo } from \"../utils\";\nimport reportIcon from \"../assets/images/icon-report.png\";\n\n/*\n * A component to handle flagging videos for abusive content. Takes care of\n * calling the backend canister to flag, and keeps state.\n */\nexport default function FlagButton({ currentUserId, videoInfo }) {\n // Keep local track of whether video is flagged so we can update the state\n // immediately rather than wait for backend call.\n const [localFlags, setLocalFlags] = useState(\n Number(videoInfo.abuseFlagCount)\n );\n // Keeps track of whether user has already flagged this video.\n const [isActive, setActive] = useState(videoInfo.viewerHasFlagged);\n const handleClick = async () => {\n if (!isActive) {\n setActive(true);\n setLocalFlags(localFlags + 1);\n return putAbuseFlagVideo(currentUserId, videoInfo.videoId, true);\n }\n };\n\n const isDisabled = localFlags < 1 || isActive;\n\n return (\n \n \n {Number(localFlags)}/10\n \n );\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAAuCAYAAAC1ZTBOAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGuSURBVHgB7ZjxTcJAFMYfhf9twwJ1A3SC4gTGBVAWME6gTqATYNmACaQ4gGEDuwEsQPV79pEQ0mivfXdAcr/ky1HaS3957V3u2iGwWq0SNI9IjGTIcxRFOVkG9+UmREbIAEnkOJRL3uAx7ojgfK9/jlzggjXZk0uoLEzyx6VzOFwFRVHcVpyMN5vNNVmQQyLcM6WyMEmdfj1yhFRviEyCIIhN+gbkABF8Qt6pfO+NsFpJkTtHJlTz0VZhrZIieI98UgtBRr2SkAtl0G2ntNaoSLIYmgFGLcuNut1uSIoYSUKGJ9yBHJ7J71jaEKOWbGBayRdq+X41wckU1BYvqYWX1MJLauEltTgJSWcrcwN4X5VziwXLB/9xDJIsNUMWSFa1Sz2kZIZV0wzVmv63Kz2E5BcyhlhWt4NrSd7G3pju511KvkLugRrgYgriHdldU0HGtmSKXEIwpRbYeNw8v00xclPILUkBDcnfyRdiC55S8HvZ7/dVP3QZSaIyQ9m+bresa1tf3nYxrqRIWRfbxa+CtPCSWnhJLbykFl5SCy+pRQ/Lqwzt9/4JfJzP6Uj4AQ2rfIRPbkwuAAAAAElFTkSuQmCC\"","import React from \"react\";\nimport iconSuperLike from \"../assets/images/icon-superlike.png\";\n\nexport default function SuperLikeButton({\n handleSuperLike,\n isSuperLiked,\n disabled,\n}) {\n return (\n \n \n \n );\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAwCAYAAABwrHhvAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAI2SURBVHgBvZjhVcIwFIVfi/xFmMCwCWzgBsgEuoFlAnECygSOABvoBsb/cKwDAN5Ao6U0TV4a+p3TU0ti3817uQmBKBCbzeb++8Qb5/8iCgCCCtxWuNSdBoOB83tjCsNCBwcfxKCxAIz+GbeRfj4cDl/EoJGAPPVJ8TMIaCcDCN6nU93P6Ha778TAW8B+v5/Tf93/2O12P8TASwAs9xDH8cTQzCoB24Z53VWa+xXNGSw4IAY+GVgZgitYo2cLyC0nTO1wAKv+LAEIPqKS5SoEXCcDed0Xtn5cCzoLgOUSqkm9BhZkrYKKG1sHjP4Rtwm5IYlJZAkuyGy5MmwLKmwlqLNcGfYErBVgs1wZHwsaBbhYrkJAmAy4Wu7iRXF8Rx5cTMLtdpvWbDQ21oy+Ga7lmYDccnNqjywqBBe4fVK7pEUBKrig9pC4xjd5cJblQtDpdJJerycjdaDAA+swEYA1Fs2x+iNG8BdqFzX7p/pBrQOuS20oXjF6qR8iNfux3T7B+7fu7zgeRATxkQg+LH7gfTaE8BUVTkSODIujVzQ5GWXM/rNy8KYCOHNHpT6pamhLwNjU0IaAytSHECAc+kiybG6hfqAwMcXos+AC8p3TRorga1sn3wwIS7vENSMHrOcCH/RO59LXKwM4AYma5hTBl+SIl4AoikwWlOSYeo1vCSoFcFKvCTkJWalvJKBi61ZeZ6W+kQC6LEHtcnttAer7nfdZIsQcmFIDvATgK5yabMe6+6Ze8wtslMICjlbF3AAAAABJRU5ErkJggg==\"","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAwCAYAAAB5R9gVAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGJSURBVHgB7ZhBTgIxFIb/dsZolMXcgJoYE1eMJ3BuIDfQI7Aj0YW4cOVGj8AN8AZ4AsaViS4oN2CBaERaXw0kZIQ8TAiyeF8yycx02n7t67ykVS/m0mOD0NgwRIhDhDhEiEOEOESIQ4Q4RIhDhDhEiEOEOESIQ9Om7NrDW/w//eCipk/P5uI8hj4luSrWSxtQrTcMmsf2rq+KpR1TS3ZRykBiVFihVylWSIiGgmqP4R8/MGwFidlyRVvpLi2kxoG9ac5rIAjuYC+NoCoObj+CLlOjCV2GGk7ok6RQhabe00hVuGy4p25yCkdviEG7KDDl1dQzj/hKzeztLX6m7/P+0N7mWANdUzdfiM48VA2TgakFhw02yHm4B4ft/Mg2LFZAxzSSEt7TMaKqhjrBnOWgljz9CNOcO/gnDd31GPc0HIXG9begf4VgBEchjSmkPnHQKa3FcuicQmi4jmIsR5jOjEaVhWWpKH35SQobLagw/Vv+mugkU3OIEIcIcYgQhwhxiBCHCHGIEMc3gOd6wqFIQH4AAAAASUVORK5CYII=\"","import React, { useEffect, useState, useRef } from \"react\";\nimport debounce from \"lodash.debounce\";\n\nimport { putRewardTransfer } from \"../utils\";\nimport tipIcon from \"../assets/images/icon-tip-active.png\";\nimport \"./TippingButton.scss\";\n\nconst DEFAULT_TIPPING_AMOUNT = 1;\n\nexport default function TippingButton({\n senderId,\n currentRewardPoints,\n recipientId,\n onRefreshUser,\n}) {\n const [isDisabled, setDisabled] = useState(false);\n const [activeAnimations, setActiveAnimations] = useState([]);\n const [animationId, setAnimationId] = useState(0);\n const [localRewardPoints, setRewardPoints] = useState(currentRewardPoints);\n const [tippingPoints, setTippingPoints] = useState(1);\n\n // The save tipping function gets debounced so it collects tips from the last\n // 5 seconds and applies them all at once. If the amount of tips is over a\n // certain threshold, show the user a confirmation.\n const saveTipping = async (localTippingPoints) => {\n setTippingPoints(1);\n await putRewardTransfer(senderId, recipientId, BigInt(localTippingPoints));\n onRefreshUser();\n };\n const saveTippingDebounced = useRef(debounce(saveTipping, 3000));\n\n // On click store the accumulated tipping points for multiple clicks and call\n // the debounced tip saving function to save on the backend\n const handleClick = async (ev) => {\n ev.preventDefault();\n if (isDisabled) return;\n setRewardPoints(localRewardPoints - DEFAULT_TIPPING_AMOUNT);\n setTippingPoints(tippingPoints + DEFAULT_TIPPING_AMOUNT);\n saveTippingDebounced.current(tippingPoints);\n setAnimationId((prevId) => prevId + 1);\n const currentId = animationId;\n setActiveAnimations((prev) => [...prev, currentId]);\n setTimeout(() => {\n setActiveAnimations((prev) => prev.filter((id) => id !== currentId));\n }, 4000);\n };\n\n useEffect(() => {\n setRewardPoints(currentRewardPoints);\n if (currentRewardPoints < DEFAULT_TIPPING_AMOUNT) {\n setDisabled(true);\n }\n }, [currentRewardPoints]);\n\n useEffect(() => {\n if (senderId === recipientId) setDisabled(true);\n }, []);\n\n return (\n \n 0 ? \"active\" : \"default\"}\n alt=\"icon: video reward points\"\n />\n {localRewardPoints}\n
\n {activeAnimations.map((id) => (\n \n \"tips\"\n
\n ))}\n \n \n );\n}\n","export default __webpack_public_path__ + \"static/media/cancan-logo.38c28168.png\";","import React, { PropsWithChildren, useEffect } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport logo from \"../assets/images/cancan-logo.png\";\nimport { useAuth } from \"../utils\";\n\n/*\n * The sign-in process for when a user has not yet authenticated with the\n * Internet Identity Service.\n */\nexport function SignIn(props: PropsWithChildren<{}>) {\n const { children = \"Authorize\" } = props;\n const auth = useAuth();\n const history = useHistory();\n\n // If the auth provider has a user (which could be from local storage) and\n // the user is properly authenticated with the identity provider service then\n // send the user to their feed, as they are correctly signed in.\n useEffect(() => {\n if (auth.user && !auth.identity?.getPrincipal().isAnonymous()) {\n history.replace(\"/feed\");\n }\n }, [auth.identity, auth.user, history]);\n\n // Initiates the login flow with the identity provider service, sending the\n // user to a new tab\n const handleLogin = async () => {\n await auth.logIn();\n history.push(\"/sign-up\");\n };\n\n return (\n
\n \"cancan\n \n
\n );\n}\n","import React from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport \"./LoadingIndicator.scss\";\n\ninterface LoadingIndicatorProps {\n loadingMessage?: string;\n completedMessage?: string;\n isLoading?: boolean;\n}\n\nexport function LoadingIndicator({\n loadingMessage = \"Loading...\",\n completedMessage,\n isLoading = true,\n}: LoadingIndicatorProps) {\n // Adding the `.completed-message` class will delay the fade-out for 1s to\n // allow the user to see the updated message before it disappears.\n const showCompletedMessage = completedMessage ? \"completed-message \" : \"\";\n const timeout = completedMessage ? 2000 : 1000;\n\n return (\n \n
\n
\n

\n {isLoading ? loadingMessage : completedMessage ?? loadingMessage}\n

\n
\n
\n \n );\n}\n","import React, { FormEvent, useEffect, useRef, useState } from \"react\";\nimport {\n checkUsername,\n createUser,\n getUserFromCanister,\n getUserNameByPrincipal,\n useAuth,\n} from \"../utils\";\nimport logo from \"../assets/images/cancan-logo.png\";\nimport { LoadingIndicator } from \"./LoadingIndicator\";\nimport { useHistory } from \"react-router\";\nimport \"./SignUp.scss\";\n\n/*\n * This component receives the authentication information and queries to see if\n * the principal returned from Identity Service matches an existing userId. If\n * it does, we set the match as the currentUser and redirect to the /feed route.\n * If the principal does not match an existing userId, the user creates one with\n * the provided form and submits, receiving an error if the name is already\n * taken, and being redirected to the /feed route on success.\n */\n\nexport function SignUp() {\n const [error, setError] = useState(\"\");\n const [isCheckingICForUser, setIsCheckingICForUser] = useState(false);\n const [isSigningIn, setIsSigningIn] = useState(false);\n const usernameInputRef = useRef(null);\n const auth = useAuth();\n const history = useHistory();\n\n // Get a user name from the user's principal and then fetch the user object\n // with all the user's data. Show a loading message between these async\n // backend calls happening.\n useEffect(() => {\n if (!auth.isAuthReady) return;\n if (auth.isAuthenticated && auth.identity !== undefined) {\n setIsCheckingICForUser(true);\n getUserNameByPrincipal(auth.identity.getPrincipal()).then((userName) => {\n if (userName) {\n // User exists! Set user and redirect to /feed.\n getUserFromCanister(Array.isArray(userName)?userName[userName.length-1]:userName).then((user) => {\n setIsCheckingICForUser(false);\n auth.setUser(user!);\n history.replace(\"/feed\");\n });\n setIsCheckingICForUser(false);\n } else {\n // Do nothing. Allow the user to create a userId\n setIsCheckingICForUser(false);\n }\n });\n }\n }, [auth.isAuthReady, auth.isAuthenticated, auth.identity]);\n\n // Submit the form to signup with a new username, the backend ensures that\n // the username is available.\n async function submit(evt: FormEvent) {\n evt.preventDefault();\n evt.stopPropagation();\n setError(\"\");\n\n // Get the username entered from the form.\n const username = usernameInputRef?.current?.value!;\n setIsSigningIn(true);\n // Check to make sure this username has not been taken. If this user already\n // has a username, it should have signed them in already.\n const isAvailable = await checkUsername(username);\n\n if (isAvailable) {\n // Create a user on the backend and assign that user to frontend data.\n const user = await createUser(username, auth.identity?.getPrincipal());\n auth.setUser(user);\n setIsSigningIn(false);\n history.push(\"/feed\");\n } else {\n setError(`Username '${username}' is taken`);\n setIsSigningIn(false);\n }\n }\n\n return (\n
\n \n \n\n
\n \"cancan\n\n
\n \n \n {error !== \"\" && (\n \n )}\n
\n \n
\n
\n );\n}\n","import React, { useEffect, useState } from \"react\";\nimport { getFeedVideos } from \"../utils\";\nimport { Video } from \"../components/Video\";\nimport { LoadingIndicator } from \"../components/LoadingIndicator\";\nimport { ProfileInfoPlus, VideoInfo } from \"../utils/canister/typings\";\n\n/*\n * Nothing fancy here, either!\n */\nexport function Feed({\n profileInfo,\n onRefreshUser,\n}: {\n profileInfo?: ProfileInfoPlus;\n onRefreshUser: any;\n}) {\n const [feed, setFeed] = useState([]);\n const [isLoading, setIsLoading] = useState(false);\n\n useEffect(() => {\n if (profileInfo && profileInfo.userName) {\n setIsLoading(true);\n getFeedVideos(profileInfo.userName)\n .then((videos) => {\n setFeed(videos);\n setIsLoading(false);\n })\n .catch((e) => {\n console.error(e);\n setIsLoading(false);\n });\n }\n }, [profileInfo?.userName]);\n\n return (\n
\n \n
\n {profileInfo &&\n feed.map((v) => (\n \n ))}\n
\n
\n );\n}\n","import React, { PropsWithRef, useEffect, useRef, useState } from \"react\";\nimport debounce from \"lodash.debounce\";\nimport { ProfileInfoPlus, VideoInfo } from \"../utils/canister/typings\";\nimport { SearchVideoItem } from \"../components/SearchVideoItem\";\nimport { Video } from \"../components/Video\";\nimport { getSearchVideos } from \"../utils\";\nimport { LoadingIndicator } from \"../components/LoadingIndicator\";\nimport \"./Discover.scss\";\n\ninterface DiscoverProps {\n profileInfo?: ProfileInfoPlus;\n}\n\n/*\n * Allows searching for and viewing videos. Nothing especially fancy here, just\n * the typical debounced input fetching data on change.\n */\nexport function Discover(props: PropsWithRef) {\n const { profileInfo } = props;\n\n const [videos, setVideos] = useState([]);\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [videoPreview, setVideoPreview] = useState();\n const [isLoading, setLoading] = useState(false);\n\n function handleChange(val: string) {\n setSearchTerm(val);\n }\n\n useEffect(() => {\n if (profileInfo) {\n setLoading(true);\n getSearchVideos(profileInfo.userName, searchTerm.split(/\\W+/), [10]).then(\n (searchedVideos) => {\n setVideos(searchedVideos);\n setLoading(false);\n }\n );\n }\n }, [searchTerm, profileInfo]);\n\n const searchRef = useRef(null);\n const debouncedChangeHandler = debounce(function () {\n handleChange(searchRef?.current?.value || \"\");\n }, 300);\n\n function handleClick(clickedVideo: VideoInfo) {\n setVideoPreview(clickedVideo);\n }\n\n return (\n
\n \n {videoPreview && profileInfo !== undefined && (\n setVideoPreview(undefined)}\n key={videoPreview.videoId}\n />\n )}\n\n
\n \n \n \n
\n
\n {searchTerm ? (\n
\n {videos.length > 0 &&\n videos.map((v) => (\n \n ))}\n
\n ) : (\n <>\n
\n New for you\n
\n {videos.length > 0 &&\n videos.map((v) => (\n \n ))}\n
\n
\n
\n Trending\n
\n {videos.length > 0 &&\n videos.map((v) => (\n \n ))}\n
\n
\n \n )}\n
\n
\n );\n}\n","import React, { ChangeEvent, useEffect, useRef, useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { ProfileInfoPlus } from \"../utils/canister/typings\";\nimport { useUploadVideo } from \"../utils\";\nimport { LoadingIndicator } from \"./LoadingIndicator\";\nimport \"./Upload.scss\";\n\n/*\n * Allows selection of a file followed by the option to add a caption before\n * uploading to the canister. Utility functions assist in the data translation.\n */\nexport function Upload({\n user,\n onUpload,\n}: {\n user?: ProfileInfoPlus;\n onUpload: () => void;\n}) {\n const history = useHistory();\n const [videoFile, setVideoFile] = useState();\n const [videoPreviewURL, setVideoPreviewURL] = useState(\"\");\n const [uploading, setUploading] = useState(false);\n const [uploadingClean, setUploadingClean] = useState(true);\n const inputRef = useRef(null);\n const textAreaRef = useRef(null);\n const videoUploadController = useUploadVideo({\n userId: user?.userName || \"\",\n });\n\n useEffect(() => {\n inputRef.current?.click();\n }, []);\n\n useEffect(() => {\n if (uploading && uploadingClean) {\n setUploadingClean(false);\n }\n }, [uploading]);\n\n useEffect(() => {\n if (videoFile) {\n // Create video preview so the user can see what they've selected\n videoFile.arrayBuffer().then((buffer) => {\n const videoBlob = new Blob([buffer], {\n type: \"video/mp4\",\n });\n const vidURL = URL.createObjectURL(videoBlob);\n setVideoPreviewURL(vidURL);\n });\n }\n }, [videoFile]);\n\n function onChange(evt: ChangeEvent) {\n const { files } = evt.target;\n if (files && files.length === 1 && files.item(0)) {\n const file = files[0];\n setVideoFile(file);\n }\n }\n\n // Wraps and triggers several functions in the videoUploadController to\n // generate a videoId and begin uploading.\n function upload() {\n const caption = textAreaRef.current?.value;\n if (!videoFile || !caption) {\n return;\n }\n videoUploadController.setFile(videoFile);\n videoUploadController.setCaption(caption);\n videoUploadController.setReady(true);\n setUploading(true);\n }\n\n // On upload success, wait 2 seconds and then redirect to /feed\n useEffect(() => {\n if (videoUploadController.completedVideo !== undefined) {\n setUploading(false);\n onUpload();\n setTimeout(() => {\n history.push(\"/feed\");\n }, 2000);\n }\n }, [videoUploadController.completedVideo]);\n\n return (\n \n \n \n {videoFile && (\n
\n
\n )}\n \n );\n}\n","export default __webpack_public_path__ + \"static/media/rewards-view.caffbbcc.png\";","import React from \"react\";\nimport rewardsView from \"../assets/images/rewards-view.png\";\n\n/*\n * Stand-in for eventual Rewards View\n */\nexport function Rewards() {\n return (\n \n );\n}\n","import React from \"react\";\nimport \"./FollowButton.scss\";\n\nexport function FollowButton({ isFollowing, handleFollow }) {\n return (\n \n {isFollowing ? \"Unfollow\" : \"Follow\"}\n \n );\n}\n","import React, { useState } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport { ProfilePic } from \"./ProfilePic\";\nimport { FollowButton } from \"./FollowButton\";\nimport \"./FollowUserRow.scss\";\n\n/*\n * A single instance of a row in the Followers/Following Profile views. Displays\n * the user's profile picture and username as a link to their profile, along\n * with a button to follow/unfollow that user.\n */\nexport function FollowUserRow({\n userName,\n handleFollow = () => {},\n following = false,\n disableFollow = false,\n}: {\n userName: string;\n handleFollow?: (userName: string, willFollow: boolean) => void;\n following?: boolean;\n disableFollow?: boolean;\n}) {\n const [isFollowing, setIsFollowing] = useState(following);\n\n // Instead of waiting for the return from the canister update call, we\n // optimistically update the UI\n function handleFollowClick(event) {\n event.preventDefault();\n setIsFollowing((state) => !state);\n handleFollow(userName, !isFollowing);\n }\n\n return (\n \n
\n \n {userName}\n {disableFollow ? (\n
\n ) : (\n \n )}\n
\n \n );\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADOSURBVHgB7dvBDcIwEETREY3jDkIHcYWkhMW75AbElhASWf8nuYD5SU5WJADA/zOzazvbfhbNpA1e7VXRDD6Md5uyOxifP0BnvLspq4HxVVkxnvGMZzzjGc/4qqwYz3jGM57xjGd8VVaMZ/yc45dpxzt73taccvxFv2fKrj3l0vkEVmXnrzoRiECEQAQRIRBBRAhEEBECEUSEQAQRIRBBRAhEEBECEUSEMBKhHaU2EKEou06E/P8LuIMIcwRw9v7ecbr/hvz+8b6fIgDA9x59me4RNVbpiAAAAABJRU5ErkJggg==\"","import React, { useEffect, useState } from \"react\";\nimport { Link, useParams, useHistory } from \"react-router-dom\";\nimport * as H from \"history\";\nimport { FollowUserRow } from \"../components/FollowUserRow\";\nimport { ProfilePic } from \"../components/ProfilePic\";\nimport { Video } from \"../components/Video\";\nimport { LoadingIndicator } from \"../components/LoadingIndicator\";\nimport { FollowButton } from \"../components/FollowButton\";\nimport {\n fileToImgSrc,\n follow,\n getProfilePic,\n getUserFromCanister,\n formatBigNumber,\n} from \"../utils\";\nimport backIcon from \"../assets/images/icon-back.png\";\nimport \"./Profile.scss\";\nimport { ProfileInfoPlus, VideoInfo } from \"../utils/canister/typings\";\n\ntype ProfileByIdParams = {\n userId: string;\n};\n\n/*\n * Nothing specific to the IC going on here, just fetching data as per usual.\n * This file does a lot of view juggling based on a lot of currentUser data.\n * There are 2 primary views: viewing another user or viewing yourself.\n * There are 4 secondary views: a list of uploaded videos, list of followers,\n * list of users the user follows, and a video preview of any uploaded videos.\n */\nexport function Profile({\n currentUser,\n onLogOut,\n}: {\n currentUser?: ProfileInfoPlus;\n onLogOut?: (history: H.History) => any;\n}) {\n const { userId = currentUser?.userName } = useParams();\n const [activeSubView, setActiveSubView] = useState(0);\n const history = useHistory();\n const { goBack } = useHistory();\n\n const [userProfile, setUserProfile] = useState();\n const [profilePic, setProfilePic] = useState(\"\");\n const [videoPreview, setVideoPreview] = useState();\n const [isLoading, setLoading] = useState(false);\n\n const currentUserFollows =\n currentUser?.following.map(({ userName }) => userName) || [];\n const initialIsFollowed = currentUserFollows.indexOf(userId || \"\") !== -1;\n const [isFollowed, setIsFollowed] = useState(initialIsFollowed);\n\n const isCurrentUserProfile = !userId || userId === currentUser?.userName;\n\n function handleShowVideoPreview(clickedVideo: VideoInfo) {\n setVideoPreview(clickedVideo);\n }\n\n async function fetchUserProfile() {\n if (isCurrentUserProfile) {\n setUserProfile(currentUser);\n return;\n }\n try {\n setLoading(true);\n const profileData = await getUserFromCanister(userId || \"\");\n setUserProfile(profileData!);\n } catch (error) {\n console.error(`Failed to retrieve profile for user ${userId}`, error);\n } finally {\n setLoading(false);\n }\n }\n\n async function fetchProfilePic() {\n try {\n const picData = await getProfilePic(userId || \"\");\n if (picData !== null) {\n const imgSrc = fileToImgSrc([picData]);\n setProfilePic(imgSrc);\n } else {\n console.info(`No profile pic set for user ${userId}`);\n }\n } catch (error) {\n console.error(\"Failed to retrieve profilePic.\", error);\n }\n }\n\n useEffect(() => {\n Promise.all([fetchUserProfile(), fetchProfilePic()]);\n }, []);\n\n function handleFollow(userToFollow: string, willFollow: boolean) {\n follow(userToFollow, currentUser?.userName || \"\", willFollow);\n }\n\n function handleFollowCurrent() {\n setIsFollowed((state) => !state);\n handleFollow(userName, !isFollowed);\n }\n\n // @ts-ignore\n const { userName = \"\", uploadedVideos = [], followers = [], following = [] } =\n userProfile ?? {};\n\n return (\n <>\n {!isCurrentUserProfile && (\n
\n \n

{userName}

\n \n
\n )}\n
\n \n {videoPreview && (\n setVideoPreview(undefined)}\n key={videoPreview.videoId}\n />\n )}\n
\n \n

\n {isCurrentUserProfile ? (\n <>\n {userId}\n
\n onLogOut && onLogOut(history)}\n >\n Log out\n \n \n ) : (\n \n )}\n

\n
\n {[\n [\"Videos\", uploadedVideos.length],\n [\"Followers\", followers.length],\n [\"Following\", following.length],\n ].map(([label, count], index) => (\n setActiveSubView(index)}\n isActive={index === activeSubView}\n label={label}\n count={count}\n />\n ))}\n
\n
\n {activeSubView === 0 && (\n
\n {uploadedVideos.length > 0 ? (\n uploadedVideos.map((uploadedVideo) => (\n handleShowVideoPreview(uploadedVideo)}\n />\n ))\n ) : (\n
\n No videos yet\n {isCurrentUserProfile && (\n \n \n \n )}\n
\n )}\n
\n )}\n {activeSubView === 1 && (\n
\n {followers.length > 0 ? (\n followers.map((follower) => (\n \n ))\n ) : (\n
No followers yet!
\n )}\n
\n )}\n {activeSubView === 2 && (\n
\n {following.length > 0 ? (\n following.map((following) => (\n \n ))\n ) : (\n
Not following anyone yet!
\n )}\n
\n )}\n
\n \n );\n}\n\nfunction ProfileNavLink({ isActive, onClick, label, count }) {\n return (\n \n
{formatBigNumber(count)}
\n {label}\n \n );\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAISSURBVHgB7ZnRbcIwEIYvUJ5bNnAnKHSC0EVgg8IEDRO0TEA6QcUEsAFsUPcdBH1GkP7XnFsrBCnBiPDgTzrFic/OH9vnOE5AJViv13c4PMNCmJLLC9io2WzObN/lctmr1+td8WU4P4bfO5UgKOoIcQqHqSUsS4SbD8X3hc+P+GlYB76aziVQWm4u4jawEaUtQvv9vler1bqSHiB9a4mLYRMug+sPyO9LHRrWhsgNnQPuLohM1imKDh8gknzbohw/JXUkq9WqX+TetSJOQRCEktR5XYNrEUmLWn5Rjh+XXciponMJtCvNa0EG3TcxaQRHlOeDsi2SoGk0GnMqwI1VWNF/xB2Dx+InfGNKRX9bebcmsd1u7+HTs/PwAPeUzgC/7Ha7IONj4HG5MD0ViLgxDnnOVfIGkQN+ilecmAGrqTyqgM9GrFSdaPUhWVEVkQOoI7QiOCQHWIuZNThIeFxRkiSargRLy13RKK4ML9CVqxfI0wyvUEKYRliXWgplUGbRAGLU9UUnIvUo2CyQ188HFXw3XhCeN9vmTaIoFdmSjAVVA9+fpz1N2TUjJsdYJscpVQTfWzSMzTUfxa54ga54ga54ga54ga54ga54ga54ga5cvcAbugBYIdOp2AK1HFuueysZiu6D87eI4gT2F2cHhTP70FUyx8fSozn5G4Oyod2Rb+NzbG4nJY3HAf8leLIr+QEY/xngEDD+GQAAAABJRU5ErkJggg==\"","import React, { useEffect, useState } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { isDropDay, REWARDS_CHECK_INTERVAL } from \"../utils\";\nimport giftIcon from \"../assets/images/icon-rewards.png\";\nimport tokenIcon from \"../assets/images/icon-tokens.png\";\nimport chevron from \"../assets/images/icon-back.png\";\nimport close from \"../assets/images/icon-close.png\";\n\nimport \"./DropDayNotification.scss\";\n\n// We track this in localStorage so as not to repeatedly alert the user\nconst DROP_DAY_LS_KEY = \"ic-can-can-dropday-alerted\";\n\nfunction getAlerted(): boolean {\n return localStorage.getItem(DROP_DAY_LS_KEY) === \"true\";\n}\nfunction setAlerted() {\n localStorage.setItem(DROP_DAY_LS_KEY, \"true\");\n}\n\n/*\n * This functions as an alert to let the user know they can convert their earned\n * rewards into tokens or merchandise, and direct them to the /rewards route.\n */\nexport function DropDayNotification() {\n const [isVisible, setIsVisible] = useState(false);\n\n function closeAlert() {\n setAlerted();\n setIsVisible(false);\n }\n\n // We poll the canister periodically to determine if `isDropDay` has changed\n function pollIsDropDay() {\n isDropDay()\n .then((result) => {\n if (result && !getAlerted()) {\n setIsVisible(result);\n }\n })\n .catch((err) => {\n // nothing to do here\n console.error(err);\n });\n }\n const interval = setInterval(pollIsDropDay, REWARDS_CHECK_INTERVAL);\n\n useEffect(() => {\n pollIsDropDay();\n return () => clearInterval(interval);\n }, []);\n\n return (\n \n
\n
\n \"Rewards\"\n \n \"Tokens\"\n
\n
\n
Today is Drop Day!
\n
\n Exchange your Reward Points for tokens or prizes.\n \n View now.\n \n
\n
\n \n
\n \n );\n}\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAmCAYAAACCjRgBAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJ6SURBVHgB7VjRcdswDKW6QJ0NlA08gtMF2g3sTJB0AnmDbFB2g7QLlNmgnSDsBE0mKALEYEIjgERJtpUPvTtccqYIvEeC0vE5dwAAwMINxJi5o0HFMRqMBwyPUYvxFUbkWCtjgccad2pg0SsmLkFCvjA5ichj342xtTs2slUtIUUCtxzREHul5CsW8qH0QSYe8F+KGuMR42tVVef4948xjZ6JNB3D6vWfnOMS4y/npsX4TTXdWGCSpWiHtKoL2D8DCbfKqiYEY7cajJrzbUU+D+JslRKvlUJtxENaMXg9oBIRuD04f2gZk7V9kRCwV7Xm8Q3sr25oIZ5261qZY+XrEtKoQqD/qkZR6FYhvhA7uhVkfIeQz1275UasamqlG4WU+XGCjvaAnruVkurKdmNBEhfC80JLVwhFyKZlt7yY+yJEClgqhYIsoAj44QYCdq/LrvxeGSORIL8Dj24YHtxwDK35jOIP2XvFLGBqzAKmxixgaswCpsYsYGrMAqbGoQSc1F3ja8BZ/kPJhYbQQHYfFRcaDz3cA3jrdmyyMXm99Yk4RoVxKS80g+6jMMA9YHKlbsd/jF8slohfCC73Mrl2N65bRBa7B6CbBt7In4ivDOL/QFxvcxEHdw+gn9txz3OI+Dnsux02cUPIodyDEuIv5DDOYN/toB35BkOseEVIBLbDwd6tNnd6DcaqMvHcWkytVLuxAN2VbjsDALYzl4sl4hU/I4mvungVfwfQQb4zXGQyl+gMfFSmkeMAPGZt/wUGvU1u+DnK9wlrUdy5YwHsPvfKbiUE2LWX51XOQa107U4JeLXDIyjOXCYyynbgtvPQ581yLIwpPpb4E152X9ALYK8ZAAAAAElFTkSuQmCC\"","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAEiSURBVHgB7dbRzYIwFAXgWyf6R2CD3w1kBEdwA0egIziBbqBu4CYeS9QEDeC97Wl56UkaHyiHLxXSitTULBs3dQFAE376cXXOHSRDop8RbuzwmU7IiX5GmLjGeGjIEdw7zffc1cj9fxO9LQP56mgnLjeiKGgwn2jkzMq9868t8mykAuctfVQkHcdEZsMxkNlxKchiuBhkcZwFiaVwBuRyuESkl5IxIr0sESXSS0JWkhaQ5vCD31/rMPTzJBNXFhmJK4NU4DwyHNVouMHcskhEbF/FkEjYW6Hbu53EBoSNPxsSxFOJEinqhMl7Fs6A3FnKLkycEnmzFJ3YuEF3N9F9tpRsc+BmkPcwNtaSFs+/+gbL+6Hv3/WrFsaxXxCpqamJywNAqMekVgOW7gAAAABJRU5ErkJggg==\"","import React, { useEffect, useState } from \"react\";\n\nimport { ProfileInfoPlus, Message } from \"../utils/canister/typings\";\nimport { getMessages, REWARDS_CHECK_INTERVAL } from \"../utils\";\nimport LottieAnimation from \"./LottieAnimation\";\nimport RewardPointAnim from \"../assets/animations/RewardPointShower.json\";\nimport \"./RewardShowerNotification.scss\";\n\nconst KEY_LOCALSTORAGE_READ_MESSAGES_TIME = \"ic-can-can-read_messages\";\n\ninterface RewardShowerProps {\n currentUser: ProfileInfoPlus;\n}\n\n// Count up all the reward points from a message\nfunction rewardPointsReducer(acc: number, message: Message) {\n const { event } = message;\n let reward = 0;\n\n if (!event) return acc;\n // @ts-ignore\n if (event.uploadReward) reward = Number(event.uploadReward.rewards);\n // @ts-ignore\n if (event.superlikerReward) reward = Number(event.superlikerReward.rewards);\n // @ts-ignore\n if (event.transferReward) reward = Number(event.transferReward.rewards);\n return acc + reward;\n}\n\n// Filter messages based on the last date they were read, stored in localStorage\nfunction unreadMessagesFilter(message: Message) {\n const lastReadTime = localStorage.getItem(\n KEY_LOCALSTORAGE_READ_MESSAGES_TIME\n );\n if (!lastReadTime) return true;\n return message.time > BigInt(lastReadTime);\n}\n\nexport function RewardShowerNotification(props: RewardShowerProps) {\n const [currentRewards, setRewards] = useState(0);\n const [isDismissed, setDismissed] = useState(false);\n\n // Checks the user's events and pulls out any reward points for unread messages\n function checkForNewMessages() {\n getMessages(props.currentUser.userName).then((messages) => {\n const unreadMessages = messages.filter(unreadMessagesFilter);\n if (unreadMessages.length === 0) return;\n const rewardPoints = unreadMessages.reduce(rewardPointsReducer, 0);\n if (rewardPoints > 0) {\n setRewards(rewardPoints);\n // Clear the animation after 5 seconds, the duration of the animation\n setTimeout(clearMessages, 5000);\n }\n if (unreadMessages) {\n setDismissed(false);\n localStorage.setItem(\n KEY_LOCALSTORAGE_READ_MESSAGES_TIME,\n (Date.now() * 1000 * 1000).toString()\n );\n }\n });\n }\n\n // Clear the reward point shower notification\n function clearMessages() {\n setDismissed(true);\n setRewards(0);\n }\n\n // Check the user messages for reward messages, every minute.\n useEffect(() => {\n checkForNewMessages();\n const interval = setInterval(checkForNewMessages, REWARDS_CHECK_INTERVAL);\n return () => clearInterval(interval);\n }, []);\n\n return (\n
\n {currentRewards > 0 && !isDismissed && (\n
\n \n
\n )}\n
\n );\n}\n","import React from \"react\";\nimport { Link, NavLink } from \"react-router-dom\";\nimport homeIcon from \"../assets/images/icon-home.png\";\nimport discoverIcon from \"../assets/images/icon-discover.png\";\nimport uploadIcon from \"../assets/images/icon-upload.png\";\nimport rewardsIcon from \"../assets/images/icon-rewards.png\";\nimport profileIcon from \"../assets/images/icon-profile.png\";\n\nimport \"./MainNav.scss\";\n\nfunction getPathRoot(path) {\n return path.split(\"/\")[1];\n}\n\nexport function MainNav({ paths }) {\n function setDestination(destination) {\n const index = paths.findIndex(\n (path) => getPathRoot(path) === getPathRoot(destination)\n );\n const currentIndex = paths.findIndex(\n (path) => getPathRoot(path) === getPathRoot(window.location.pathname)\n );\n\n function onClick() {\n const destinationIndex = index < 0 ? paths.length : index;\n const value = currentIndex > destinationIndex ? -100 : 100;\n document.getElementById(\n \"slide-direction\"\n )!.innerHTML = `.page-slide { --inDirection: ${value}%; }`;\n }\n\n return { to: destination, onClick };\n }\n\n return (\n