Skip to content

Commit

Permalink
QF-1965 - Add shorten url feature (#2327)
Browse files Browse the repository at this point in the history
* add shorten url feature

* add preview mode

* address comments
  • Loading branch information
AhmedCodeGuy authored Feb 25, 2025
1 parent 37a61ec commit 1338cda
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 53 deletions.
16 changes: 12 additions & 4 deletions src/components/MediaMaker/RenderControls/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import RenderVideoButton from './RenderVideoButton';
import Button, { ButtonType } from '@/dls/Button/Button';
import CopyIcon from '@/icons/copy.svg';
import layoutStyle from '@/pages/index.module.scss';
import PreviewMode from '@/types/Media/PreviewMode';
import { shortenUrl } from '@/utils/auth/api';
import { logButtonClick } from '@/utils/eventLogger';
import { getCurrentPath } from '@/utils/url';
import { getQuranMediaMakerNavigationUrl } from '@/utils/navigation';
import { getBasePath, getCurrentPath } from '@/utils/url';

type Props = {
inputProps: MediaFileCompositionProps;
Expand Down Expand Up @@ -49,11 +52,16 @@ const RenderControls: React.FC<Props> = ({ inputProps, isFetching, playerRef })
};
}, [isCopied]);

const onCopyLinkClicked = () => {
const onCopyLinkClicked = async () => {
logButtonClick('video_generation_copy_link');
const path = getCurrentPath();
if (origin) {
clipboardCopy(path).then(() => {
const response = await shortenUrl(`${path}&previewMode=${PreviewMode.ENABLED}`);

const url = response?.id
? `${getBasePath()}${getQuranMediaMakerNavigationUrl()}/${response.id}`
: path;
if (url) {
clipboardCopy(url).then(() => {
setIsCopied(true);
});
}
Expand Down
1 change: 1 addition & 0 deletions src/components/MediaMaker/Settings/VideoSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const MEDIA_SETTINGS_TO_QUERY_PARAM = {
orientation: QueryParam.ORIENTATION,
videoId: QueryParam.VIDEO_ID,
surah: QueryParam.SURAH,
previewMode: QueryParam.PREVIEW_MODE,
} as Record<keyof MediaSettings, QueryParam>;

const VideoSettings: React.FC<Props> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import CopyLinkIcon from '@/icons/copy-link.svg';
import CopyIcon from '@/icons/copy.svg';
import VideoIcon from '@/icons/video.svg';
import { selectQuranReaderStyles } from '@/redux/slices/QuranReader/styles';
import PreviewMode from '@/types/Media/PreviewMode';
import QueryParam from '@/types/QueryParam';
import Verse from '@/types/Verse';
import { logButtonClick } from '@/utils/eventLogger';
Expand Down Expand Up @@ -117,6 +118,7 @@ const ShareVerseActionsMenu: React.FC<Props> = ({
[QueryParam.SURAH]: verse.chapterId as string,
[QueryParam.VERSE_FROM]: String(verse.verseNumber),
[QueryParam.VERSE_TO]: String(verse.verseNumber),
[QueryParam.PREVIEW_MODE]: PreviewMode.DISABLED,
}),
);
};
Expand Down
6 changes: 6 additions & 0 deletions src/hooks/auth/media/useGetMediaSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import AvailableTranslation from '@/types/AvailableTranslation';
import Alignment from '@/types/Media/Alignment';
import MediaSettings from '@/types/Media/MediaSettings';
import Orientation from '@/types/Media/Orientation';
import PreviewMode from '@/types/Media/PreviewMode';
import QueryParam from '@/types/QueryParam';
import { QuranFont } from '@/types/QuranReader';
import Reciter from '@/types/Reciter';
Expand Down Expand Up @@ -66,6 +67,9 @@ const useGetMediaSettings = (
);
const { value: videoId }: { value: number } = useGetQueryParamOrReduxValue(QueryParam.VIDEO_ID);
const { value: surah }: { value: number } = useGetQueryParamOrReduxValue(QueryParam.SURAH);
const { value: previewMode }: { value: PreviewMode } = useGetQueryParamOrReduxValue(
QueryParam.PREVIEW_MODE,
);

return useMemo(() => {
return {
Expand All @@ -86,6 +90,7 @@ const useGetMediaSettings = (
orientation,
videoId,
surah,
previewMode,
};
}, [
backgroundColor,
Expand All @@ -105,6 +110,7 @@ const useGetMediaSettings = (
verseFrom,
verseTo,
videoId,
previewMode,
]);
};

Expand Down
10 changes: 10 additions & 0 deletions src/hooks/useGetQueryParamOrReduxValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
selectFontColor,
selectOpacity,
selectOrientation,
selectPreviewMode,
selectQuranTextFontScale,
selectQuranTextFontStyle,
selectReciter,
Expand All @@ -30,6 +31,7 @@ import {
DEFAULT_BACKGROUND_COLOR,
DEFAULT_BORDER_COLOR,
DEFAULT_FONT_COLOR,
DEFAULT_PREVIEW_MODE,
DEFAULT_RECITER_ID,
DEFAULT_SURAH,
DEFAULT_TRANSLATION,
Expand All @@ -48,6 +50,7 @@ import {
isValidFontStyleQueryParamValue,
isValidOpacityQueryParamValue,
isValidOrientationQueryParamValue,
isValidPreviewModeQueryParamValue,
isValidReciterId,
isValidTranslationsQueryParamValue,
isValidTranslationsQueryParamValueWithExistingKey,
Expand Down Expand Up @@ -186,6 +189,13 @@ export const QUERY_PARAMS_DATA = {
queryParamValueType: QueryParamValueType.Number,
isValidQueryParam: (val) => isValidVideoIdQueryParamValue(val),
},
[QueryParam.PREVIEW_MODE]: {
reduxValueSelector: selectPreviewMode,
reduxValueEqualityFunction: shallowEqual,
queryParamValueType: QueryParamValueType.String,
isValidQueryParam: (val) => isValidPreviewModeQueryParamValue(val),
customValueGetterWhenParamIsInvalid: () => DEFAULT_PREVIEW_MODE,
},
} as QueryParamsData;

export const getQueryParamsData = () => {
Expand Down
30 changes: 30 additions & 0 deletions src/pages/media/[shortenURL]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { GetServerSideProps } from 'next';

import { getFullUrlById } from '@/utils/auth/api';

const ShortenURL = () => {};

export const getServerSideProps: GetServerSideProps = async (context) => {
const { shortenURL } = context.query;

if (shortenURL) {
const response = await getFullUrlById(shortenURL as string);
if (response.url) {
return {
redirect: {
destination: response.url,
permanent: false,
},
};
}
}

return {
redirect: {
destination: '/media',
permanent: false,
},
};
};

export default ShortenURL;
26 changes: 16 additions & 10 deletions src/pages/media/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { getMediaGeneratorOgImageUrl } from '@/lib/og';
import Error from '@/pages/_error';
import layoutStyles from '@/pages/index.module.scss';
import AudioData from '@/types/AudioData';
import PreviewMode from '@/types/Media/PreviewMode';
import QueryParam from '@/types/QueryParam';
import { MushafLines, QuranFont } from '@/types/QuranReader';
import Reciter from '@/types/Reciter';
Expand Down Expand Up @@ -114,6 +115,7 @@ const MediaMaker: NextPage<MediaMaker> = ({
quranTextFontStyle,
translationFontScale,
orientation,
previewMode,
} = mediaSettings;

const queryParams = {
Expand All @@ -132,6 +134,7 @@ const MediaMaker: NextPage<MediaMaker> = ({
[QueryParam.QURAN_TEXT_FONT_STYLE]: String(quranTextFontStyle),
[QueryParam.TRANSLATION_FONT_SCALE]: String(translationFontScale),
[QueryParam.ORIENTATION]: orientation,
[QueryParam.PREVIEW_MODE]: previewMode,
};

useAddQueryParamsToUrl(getQuranMediaMakerNavigationUrl(queryParams), {});
Expand Down Expand Up @@ -430,16 +433,19 @@ const MediaMaker: NextPage<MediaMaker> = ({
/>
</>
</div>
<div className={layoutStyles.flow}>
<VideoSettings
chaptersList={chaptersList}
reciters={reciters}
playerRef={playerRef}
isFetching={isFetching}
inputProps={inputProps}
mediaSettings={mediaSettings}
/>
</div>

{previewMode === PreviewMode.DISABLED && (
<div className={layoutStyles.flow}>
<VideoSettings
chaptersList={chaptersList}
reciters={reciters}
playerRef={playerRef}
isFetching={isFetching}
inputProps={inputProps}
mediaSettings={mediaSettings}
/>
</div>
)}
</div>
</>
);
Expand Down
3 changes: 3 additions & 0 deletions src/redux/slices/mediaMaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
DEFAULT_BORDER_SIZE,
DEFAULT_FONT_COLOR,
DEFAULT_OPACITY,
DEFAULT_PREVIEW_MODE,
DEFAULT_QURAN_FONT_SCALE,
DEFAULT_QURAN_FONT_STYLE,
DEFAULT_RECITER_ID,
Expand Down Expand Up @@ -38,6 +39,7 @@ const initialState: MediaSettings = {
surah: DEFAULT_SURAH,
verseFrom: '1',
verseTo: '1',
previewMode: DEFAULT_PREVIEW_MODE,
};

export const mediaGeneratorSlice = createSlice({
Expand Down Expand Up @@ -84,5 +86,6 @@ export const selectSurahAndVersesFromAndTo = (state: RootState) => ({
export const selectBorderColor = (state: RootState) => state.mediaMaker.borderColor;
export const selectBorderSize = (state: RootState) => state.mediaMaker.borderSize;
export const selectBackgroundColor = (state: RootState) => state.mediaMaker.backgroundColor;
export const selectPreviewMode = (state: RootState) => state.mediaMaker.previewMode;

export default mediaGeneratorSlice.reducer;
101 changes: 62 additions & 39 deletions src/utils/auth/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import { BANNED_USER_ERROR_ID } from './constants';
import generateSignature from './signature';
import BookmarkByCollectionIdQueryParams from './types/BookmarkByCollectionIdQueryParams';
import GetAllNotesQueryParams from './types/Note/GetAllNotesQueryParams';
import { ShortenUrlResponse } from './types/ShortenUrl';

import { fetcher, X_AUTH_SIGNATURE, X_INTERNAL_CLIENT, X_TIMESTAMP } from '@/api';
import {
ActivityDay,
ActivityDayType,
FilterActivityDaysParams,
QuranActivityDay,
UpdateQuranActivityDayBody,
ActivityDayType,
UpdateActivityDayBody,
ActivityDay,
UpdateLessonActivityDayBody,
UpdateActivityDayParams,
UpdateLessonActivityDayBody,
UpdateQuranActivityDayBody,
} from '@/types/auth/ActivityDay';
import ConsentType from '@/types/auth/ConsentType';
import { Course } from '@/types/auth/Course';
Expand All @@ -34,53 +35,55 @@ import MediaRenderError from '@/types/Media/MediaRenderError';
import QuestionResponse from '@/types/QuestionsAndAnswers/QuestionResponse';
import { Mushaf } from '@/types/QuranReader';
import {
makeBookmarksUrl,
makeCompleteSignupUrl,
makeUserProfileUrl,
makeDeleteAccountUrl,
CollectionsQueryParams,
makeActivityDaysUrl,
makeAddCollectionBookmarkUrl,
makeAddCollectionUrl,
makeBookmarkCollectionsUrl,
makeBookmarksRangeUrl,
makeBookmarksUrl,
makeBookmarkUrl,
makeReadingSessionsUrl,
makeUserPreferencesUrl,
makeVerificationCodeUrl,
makeUserBulkPreferencesUrl,
makeLogoutUrl,
makeCompleteAnnouncementUrl,
makeSyncLocalDataUrl,
makeRefreshTokenUrl,
makeCollectionsUrl,
makeGetBookmarkByCollectionId,
makeAddCollectionUrl,
makeBookmarkCollectionsUrl,
CollectionsQueryParams,
makeUpdateCollectionUrl,
makeDeleteCollectionUrl,
makeAddCollectionBookmarkUrl,
makeCompleteAnnouncementUrl,
makeCompleteSignupUrl,
makeCountNotesWithinRangeUrl,
makeCountQuestionsWithinRangeUrl,
makeCourseFeedbackUrl,
makeDeleteAccountUrl,
makeDeleteBookmarkUrl,
makeDeleteCollectionBookmarkByIdUrl,
makeDeleteCollectionBookmarkByKeyUrl,
makeDeleteBookmarkUrl,
makeActivityDaysUrl,
makeGoalUrl,
makeFilterActivityDaysUrl,
makeStreakUrl,
makeEstimateRangesReadingTimeUrl,
makeUserFeatureFlagsUrl,
makeUserConsentsUrl,
makeNotesUrl,
makeDeleteCollectionUrl,
makeDeleteOrUpdateNoteUrl,
makeCountNotesWithinRangeUrl,
makeEnrollUserUrl,
makeEstimateRangesReadingTimeUrl,
makeFilterActivityDaysUrl,
makeFullUrlById,
makeGenerateMediaFileUrl,
makeGetBookmarkByCollectionId,
makeGetCoursesUrl,
makeGetCourseUrl,
makePublishNoteUrl,
makeCourseFeedbackUrl,
makeGetUserCoursesCountUrl,
makeGenerateMediaFileUrl,
makeGetMediaFileProgressUrl,
makeGetMonthlyMediaFilesCountUrl,
makeCountQuestionsWithinRangeUrl,
makeGetQuestionsByVerseKeyUrl,
makeGetQuestionByIdUrl,
makeGetQuestionsByVerseKeyUrl,
makeGetUserCoursesCountUrl,
makeGoalUrl,
makeLogoutUrl,
makeNotesUrl,
makePublishNoteUrl,
makeReadingSessionsUrl,
makeRefreshTokenUrl,
makeShortenUrlUrl,
makeStreakUrl,
makeSyncLocalDataUrl,
makeUpdateCollectionUrl,
makeUserBulkPreferencesUrl,
makeUserConsentsUrl,
makeUserFeatureFlagsUrl,
makeUserPreferencesUrl,
makeUserProfileUrl,
makeVerificationCodeUrl,
} from '@/utils/auth/apiPaths';
import { isStaticBuild } from '@/utils/build';
import CompleteAnnouncementRequest from 'types/auth/CompleteAnnouncementRequest';
Expand Down Expand Up @@ -472,6 +475,26 @@ export const addOrUpdateBulkUserPreferences = async (
mushafId: Mushaf,
) => postRequest(makeUserBulkPreferencesUrl(mushafId), preferences);

/**
* Shorten a URL.
*
* @param {string} url
* @returns {Promise<ShortenUrlResponse>}
*/
export const shortenUrl = async (url: string): Promise<ShortenUrlResponse> => {
return postRequest(makeShortenUrlUrl(), { url });
};

/**
* Get full URL by id.
*
* @param {string} id
* @returns {Promise<ShortenUrlResponse>}
*/
export const getFullUrlById = async (id: string): Promise<ShortenUrlResponse> => {
return privateFetcher(makeFullUrlById(id));
};

export const logoutUser = async () => {
return postRequest(makeLogoutUrl(), {});
};
Expand Down
15 changes: 15 additions & 0 deletions src/utils/auth/apiPaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,18 @@ export const makeGetMediaFileProgressUrl = (renderId: string) =>

export const makeGetMonthlyMediaFilesCountUrl = (type: MediaType) =>
makeUrl(`media/monthly-count`, { type });

/**
* Compose the url for shorten-url API.
*
* @returns {string}
*/
export const makeShortenUrlUrl = (): string => makeUrl('/shorten-url');

/**
* Compose the url for get full URL by id.
*
* @param {string} id
* @returns {string}
*/
export const makeFullUrlById = (id: string): string => makeUrl(`/shorten-url/${id}`);
Loading

0 comments on commit 1338cda

Please sign in to comment.