feat: updated tos and privacy policy on registration link

intial run at legal links modal
pull/3056/head
William Grant 1 year ago
parent 8dfdd87d0e
commit b10873c64a

@ -402,7 +402,6 @@
"linkDevice": "Link Device",
"restoreUsingRecoveryPhrase": "Restore your account",
"or": "or",
"ByUsingThisService...": "By using this service, you agree to our <a href=\"https://getsession.org/terms-of-service \">Terms of Service</a> and <a href=\"https://getsession.org/privacy-policy\" target=\"_blank\">Privacy Policy</a>",
"beginYourSession": "Begin your Session.",
"welcomeToYourSession": "Welcome to your Session",
"searchFor...": "Search conversations and contacts",
@ -579,5 +578,10 @@
"notApplicable": "N/A",
"unknownError": "Unknown Error",
"waitOneMoment": "One moment please...",
"loadAccountProgressMessage": "Loading your account"
"loadAccountProgressMessage": "Loading your account",
"onboardingTosPrivacy": "By using this service, you agree to our <b>Terms of Service</b> and <b>Privacy Policy</b>",
"urlOpen": "Open URL",
"urlOpenBrowser": "This will open in your browser.",
"termsOfService": "Terms of Service",
"privacyPolicy": "Privacy Policy"
}

@ -79,94 +79,6 @@
}
}
// TODO[epic=ses-50]: Remove the following styles
// &-input-floating-label-show-hide {
// padding-inline-end: 30px;
// }
// &-input-with-label-container {
// height: 46.5px;
// width: 280px;
// font-family: var(--font-default);
// color: var(--text-primary-color);
// padding: 2px 0 2px 0;
// transition: opacity var(--default-duration);
// opacity: 1;
// position: relative;
// label {
// line-height: 14px;
// opacity: 0;
// color: var(--text-primary-color);
// font-size: 10px;
// line-height: 11px;
// position: absolute;
// top: 0px;
// }
// &.filled {
// opacity: 1;
// }
// &.error {
// color: var(--danger-color);
// }
// input {
// border: none;
// outline: 0;
// height: 14px;
// width: 280px;
// background: transparent;
// color: var(--input-text-color);
// font-family: var(--font-default);
// font-size: 12px;
// line-height: 14px;
// position: absolute;
// top: 50%;
// transform: translateY(-50%);
// &::placeholder {
// color: var(--input-text-placeholder-color);
// }
// }
// hr {
// border: 1px solid var(--border-color);
// width: 100%;
// position: absolute;
// bottom: 0px;
// }
// }
&-terms-conditions-agreement {
padding-top: var(--margins-md);
color: var(--text-secondary-color);
text-align: center;
font-size: 12px;
a {
white-space: nowrap;
font-weight: bold;
text-decoration: none;
color: var(--text-secondary-color);
transition: var(--default-duration);
&:visited &:link {
color: var(--text-secondary-color);
}
&:hover {
color: var(--text-primary-color);
}
}
}
&-description-long {
padding-top: 0;
padding-bottom: 20px;

@ -15,15 +15,16 @@ import { useIsRightPanelShowing } from '../../../../hooks/useUI';
import {
ConversationInteractionStatus,
ConversationInteractionType,
showAddModeratorsByConvoId,
showInviteContactByConvoId,
showLeaveGroupByConvoId,
showRemoveModeratorsByConvoId,
showUpdateGroupMembersByConvoId,
showUpdateGroupNameByConvoId,
} from '../../../../interactions/conversationInteractions';
import { Constants } from '../../../../session';
import { MAX_USERNAME_BYTES } from '../../../../session/constants';
import { ToastUtils } from '../../../../session/utils';
import { sanitizeSessionUsername } from '../../../../session/utils/String';
import { closeRightPanel } from '../../../../state/ducks/conversations';
import { resetRightOverlayMode } from '../../../../state/ducks/section';
import { resetRightOverlayMode, setRightOverlayMode } from '../../../../state/ducks/section';
import {
useSelectedConversationKey,
useSelectedDisplayNameInProfile,
@ -41,11 +42,10 @@ import { AttachmentTypeWithPath } from '../../../../types/Attachment';
import { getAbsoluteAttachmentPath } from '../../../../types/MessageAttachment';
import { Avatar, AvatarSize } from '../../../avatar/Avatar';
import { Flex } from '../../../basic/Flex';
import { SessionButton } from '../../../basic/SessionButton';
import { SpacerLG, SpacerMD, SpacerXL } from '../../../basic/Text';
import { SessionInput2 } from '../../../inputs';
import { PanelButtonGroup, PanelIconButton } from '../../../buttons';
import { MediaItemType } from '../../../lightbox/LightboxGallery';
import { SessionProgressBar } from '../../../loading';
import { MediaGallery } from '../../media-gallery/MediaGallery';
import { Header, StyledScrollContainer } from './components';
async function getMediaGalleryProps(
@ -210,58 +210,6 @@ export const OverlayRightPanelSettings = () => {
});
const lastMessage = useSelectedLastMessage();
// TODO[epic=ses-50] move this into already have an account screen
// #region for testing
const [progress, setProgress] = useState(0);
const [inputValue, setInputValue] = useState('');
const [inputError, setInputError] = useState<string | undefined>(undefined);
function sanitizeDisplayNameOrToast(
displayName: string,
setDisplayName: (sanitized: string) => void,
setDisplayNameError: (error: string | undefined) => void
) {
try {
const sanitizedName = sanitizeSessionUsername(displayName);
const trimName = sanitizedName.trim();
setDisplayName(sanitizedName);
setDisplayNameError(!trimName ? window.i18n('displayNameEmpty') : undefined);
} catch (e) {
setDisplayName(displayName);
setDisplayNameError(window.i18n('displayNameTooLong'));
ToastUtils.pushToastError('toolong', window.i18n('displayNameTooLong'));
}
}
const handleInputChanged = (name: string) => {
sanitizeDisplayNameOrToast(name, setInputValue, setInputError);
if (name.length > 8) {
setInputError(window.i18n('displayNameTooLong'));
}
};
const handleEnterPressed = (name: string) => {
if (name) {
sanitizeDisplayNameOrToast(name, setInputValue, setInputError);
ToastUtils.pushToastSuccess('success', window.i18n('done'));
}
};
useEffect(() => {
const interval = setInterval(() => {
setProgress(oldProgress => {
if (oldProgress === 100) {
clearInterval(interval);
return 100;
}
return Math.min(oldProgress + 10, 100);
});
}, 1000);
return () => clearInterval(interval);
}, []);
// #endregion
useEffect(() => {
let isCancelled = false;
@ -332,34 +280,7 @@ export const OverlayRightPanelSettings = () => {
return (
<StyledScrollContainer>
<Flex container={true} flexDirection={'column'} alignItems={'center'}>
<SessionProgressBar
progress={progress}
width={'320px'}
margin={'var(--margins-lg) auto'}
title={window.i18n('waitOneMoment')}
subtitle={window.i18n('loadAccountProgressMessage')}
showPercentage={true}
/>
<SpacerLG />
<SessionInput2
placeholder={window.i18n('enterDisplayName')}
value={inputValue}
error={inputError}
maxLength={MAX_USERNAME_BYTES}
onValueChanged={handleInputChanged}
onEnterPressed={handleEnterPressed}
ctaButton={
<SessionButton
onClick={() => {
window.log.debug(
`WIP: [OverlayRightPanelSettings] clicked continuing your session! `
);
}}
text={window.i18n('continueYourSession')}
/>
}
/>
{/* <HeaderItem />
<HeaderItem />
<PanelButtonGroup style={{ margin: '0 var(--margins-lg)' }}>
{showUpdateGroupNameButton && (
<PanelIconButton
@ -428,7 +349,7 @@ export const OverlayRightPanelSettings = () => {
iconType={'delete'}
/>
)}
</PanelButtonGroup> */}
</PanelButtonGroup>
<SpacerLG />
<SpacerXL />
</Flex>

@ -14,6 +14,7 @@ import {
getRecoveryPhraseDialog,
getRemoveModeratorsModal,
getSessionPasswordDialog,
getTermsOfServicePrivacyModalState,
getUpdateGroupMembersModal,
getUpdateGroupNameModal,
getUserDetailsModal,
@ -32,6 +33,7 @@ import { SessionConfirm } from './SessionConfirm';
import { SessionNicknameDialog } from './SessionNicknameDialog';
import { SessionPasswordDialog } from './SessionPasswordDialog';
import { SessionSeedModal } from './SessionSeedModal';
import { TermsOfServicePrivacyDialog } from './TermsOfServicePrivacyDialog';
import { UpdateGroupMembersDialog } from './UpdateGroupMembersDialog';
import { UpdateGroupNameDialog } from './UpdateGroupNameDialog';
import { UserDetailsDialog } from './UserDetailsDialog';
@ -54,6 +56,7 @@ export const ModalContainer = () => {
const reactListModalState = useSelector(getReactListDialog);
const reactClearAllModalState = useSelector(getReactClearAllDialog);
const editProfilePictureModalState = useSelector(getEditProfilePictureModalState);
const termsOfServicePrivacyModalState = useSelector(getTermsOfServicePrivacyModalState);
return (
<>
@ -78,6 +81,9 @@ export const ModalContainer = () => {
{editProfilePictureModalState && (
<EditProfilePictureModal {...editProfilePictureModalState} />
)}
{termsOfServicePrivacyModalState && (
<TermsOfServicePrivacyDialog {...termsOfServicePrivacyModalState} />
)}
</>
);
};

@ -0,0 +1,54 @@
import { noop } from 'lodash';
import { useDispatch } from 'react-redux';
import { updateTermsOfServicePrivacyModal } from '../../state/ducks/modalDialog';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { SessionButton, SessionButtonShape, SessionButtonType } from '../basic/SessionButton';
export type TermsOfServicePrivacyDialogProps = {
show: boolean;
};
export function TermsOfServicePrivacyDialog(props: TermsOfServicePrivacyDialogProps) {
const { show } = props;
const dispatch = useDispatch();
const onClose = () => {
dispatch(updateTermsOfServicePrivacyModal(null));
};
if (!show) {
return null;
}
// TODO[epic=ses-900] need to add redux context to initial screens... or at the very least, a separate onboarding redux state
return (
<SessionWrapperModal
title={window.i18n('urlOpen')}
onClose={onClose}
showExitIcon={true}
showHeader={true}
>
<div className="session-modal__centered">
<span className="session-confirm-sub-message">{window.i18n('urlOpenBrowser')}</span>
<div className="session-modal__button-group">
<SessionButton
text={window.i18n('termsOfService')}
buttonType={SessionButtonType.Simple}
buttonShape={SessionButtonShape.Square}
onClick={noop}
dataTestId="session-tos-button"
/>
<SessionButton
text={window.i18n('privacyPolicy')}
buttonType={SessionButtonType.Simple}
buttonShape={SessionButtonShape.Square}
onClick={noop}
dataTestId="session-privacy-policy-button"
/>
</div>
</div>
</SessionWrapperModal>
);
}

@ -212,7 +212,7 @@ export const SignInTab = () => {
</Flex>
)}
{showTermsAndConditions && <TermsAndConditions />}
{showTermsAndConditions ? <TermsAndConditions /> : null}
</div>
);
};

@ -1,9 +1,33 @@
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { updateTermsOfServicePrivacyModal } from '../../state/ducks/modalDialog';
import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer';
const StyledTermsAndConditions = styled.div`
padding-top: var(--margins-md);
color: var(--text-secondary-color);
text-align: center;
font-size: 12px;
b {
font-weight: bold;
color: var(--text-primary-color);
}
&:hover {
cursor: pointer;
}
`;
export const TermsAndConditions = () => {
const dispatch = useDispatch();
return (
<div className="session-terms-conditions-agreement">
<SessionHtmlRenderer html={window.i18n('ByUsingThisService...')} />
</div>
<StyledTermsAndConditions
onClick={() => dispatch(updateTermsOfServicePrivacyModal({ show: true }))}
>
<SessionHtmlRenderer html={window.i18n('onboardingTosPrivacy')} />
</StyledTermsAndConditions>
);
};

@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { EditProfilePictureModalProps } from '../../components/dialog/EditProfilePictureModal';
import { SessionConfirmDialogProps } from '../../components/dialog/SessionConfirm';
import { PasswordAction } from '../../components/dialog/SessionPasswordDialog';
import { TermsOfServicePrivacyDialogProps } from '../../components/dialog/TermsOfServicePrivacyDialog';
import { Noop } from '../../types/Util';
export type BanType = 'ban' | 'unban';
@ -38,6 +39,8 @@ export type ReactModalsState = {
export type EditProfilePictureModalState = EditProfilePictureModalProps | null;
export type TermsOfServicePrivacyModalState = TermsOfServicePrivacyDialogProps | null;
export type ModalState = {
confirmModal: ConfirmModalState;
inviteContactModal: InviteContactModalState;
@ -56,6 +59,7 @@ export type ModalState = {
reactListModalState: ReactModalsState;
reactClearAllModalState: ReactModalsState;
editProfilePictureModalState: EditProfilePictureModalState;
termsOfServicePrivacyModalState: TermsOfServicePrivacyModalState;
};
export const initialModalState: ModalState = {
@ -76,6 +80,7 @@ export const initialModalState: ModalState = {
reactListModalState: null,
reactClearAllModalState: null,
editProfilePictureModalState: null,
termsOfServicePrivacyModalState: null,
};
const ModalSlice = createSlice({
@ -133,6 +138,12 @@ const ModalSlice = createSlice({
updateEditProfilePictureModel(state, action: PayloadAction<EditProfilePictureModalState>) {
return { ...state, editProfilePictureModalState: action.payload };
},
updateTermsOfServicePrivacyModal(
state,
action: PayloadAction<TermsOfServicePrivacyModalState>
) {
return { ...state, termsOfServicePrivacyModalState: action.payload };
},
},
});
@ -155,5 +166,6 @@ export const {
updateReactListModal,
updateReactClearAllModal,
updateEditProfilePictureModel,
updateTermsOfServicePrivacyModal,
} = actions;
export const modalReducer = reducer;

@ -1,6 +1,5 @@
import { createSelector } from '@reduxjs/toolkit';
import { StateType } from '../reducer';
import {
AddModeratorsModalState,
BanOrUnbanUserModalState,
@ -16,10 +15,12 @@ import {
RecoveryPhraseModalState,
RemoveModeratorsModalState,
SessionPasswordModalState,
TermsOfServicePrivacyModalState,
UpdateGroupMembersModalState,
UpdateGroupNameModalState,
UserDetailsModalState,
} from '../ducks/modalDialog';
import { StateType } from '../reducer';
export const getModal = (state: StateType): ModalState => {
return state.modals;
@ -109,3 +110,8 @@ export const getEditProfilePictureModalState = createSelector(
getModal,
(state: ModalState): EditProfilePictureModalState => state.editProfilePictureModalState
);
export const getTermsOfServicePrivacyModalState = createSelector(
getModal,
(state: ModalState): TermsOfServicePrivacyModalState => state.termsOfServicePrivacyModalState
);

@ -1,5 +1,4 @@
export type LocalizerKeys =
| 'ByUsingThisService...'
| 'about'
| 'accept'
| 'activeMembers'
@ -354,6 +353,7 @@ export type LocalizerKeys =
| 'oceanLightThemeTitle'
| 'offline'
| 'ok'
| 'onboardingTosPrivacy'
| 'oneNonImageAtATimeToast'
| 'onionPathIndicatorDescription'
| 'onionPathIndicatorTitle'
@ -390,6 +390,7 @@ export type LocalizerKeys =
| 'primaryColorPurple'
| 'primaryColorRed'
| 'primaryColorYellow'
| 'privacyPolicy'
| 'privacySettingsTitle'
| 'pruneSettingDescription'
| 'pruneSettingTitle'
@ -482,6 +483,7 @@ export type LocalizerKeys =
| 'startedACall'
| 'support'
| 'surveyTitle'
| 'termsOfService'
| 'themesSettingTitle'
| 'theyChangedTheTimer'
| 'theyChangedTheTimerLegacy'
@ -548,6 +550,8 @@ export type LocalizerKeys =
| 'unreadMessages'
| 'updateGroupDialogTitle'
| 'updatedTheGroup'
| 'urlOpen'
| 'urlOpenBrowser'
| 'userAddedToModerators'
| 'userBanFailed'
| 'userBanned'

Loading…
Cancel
Save