Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save Username in Local Storage only at Permission #228

Merged
merged 10 commits into from
Jan 15, 2024
34 changes: 15 additions & 19 deletions packages/frontend/src/common/dialogs/JoinSessionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
useMediaQuery,
useTheme,
Expand All @@ -17,14 +16,13 @@ import { generateId } from "../utils/generateId";

import { useBackendAdapter } from "../adapter/backendAdapter";
import { useNamespace } from "../hooks/useNamespace";
import { TextInput } from "../components/TextInput";
import { useErrorContext } from "../context/ErrorContext";
import { LocalStorage } from "../utils/localStorage";
import { useLocalStorage } from "../hooks/useLocalStorage";
import { CallToActionButton } from "../components/buttons/CallToActionButton";
import { useDialog } from "../hooks/useDialog";
import { useRedirect } from "../hooks/useRedirect";
import { useRoomIdFromPath } from "../hooks/useRoomIdFromPath";
import UserNameInputField from "../../retro/components/dialogs/UsernameInputField";
import useLocalStorageName from "../../retro/hooks/useLocalStorageName";

interface JoinSessionDialogProps {
onAddToWaitingList: ({ userId, userName }: { userId: string; userName: string }) => void;
Expand All @@ -40,6 +38,9 @@ export function JoinSessionDialog({ onAddToWaitingList }: JoinSessionDialogProps
handleChange,
isValid,
} = useValidatedTextInput({ minLength: 1, maxLength: 40 });
const { isStorageAllowed, trySavingNameLocally, handleAllowanceChange } = useLocalStorageName({
setName,
});
const { redirectBackToHome, redirectToRoom } = useRedirect();
const { setError } = useErrorContext();
const { setRoomId } = useRoomContext();
Expand All @@ -50,10 +51,6 @@ export function JoinSessionDialog({ onAddToWaitingList }: JoinSessionDialogProps
const namespace = useNamespace();
const { roomIdExists } = useBackendAdapter();

useLocalStorage(() => {
setName(LocalStorage.getUserName());
});

function handleClose() {
setName("");
closeDialog();
Expand All @@ -79,7 +76,7 @@ export function JoinSessionDialog({ onAddToWaitingList }: JoinSessionDialogProps
};
setRoomId(roomId);
setUser(newUser);
LocalStorage.setUserName(name);
trySavingNameLocally(name);
onAddToWaitingList({ userId: newUser.id, userName: name });
redirectToRoom(roomId);
handleClose();
Expand All @@ -95,18 +92,17 @@ export function JoinSessionDialog({ onAddToWaitingList }: JoinSessionDialogProps
>
<DialogTitle id="join-poker-dialog-title">Join Session</DialogTitle>
<DialogContent>
<DialogContentText>Please provide your name for this session</DialogContentText>
<TextInput
<UserNameInputField
userName={name}
label="Please provide your name for this session"
onSubmit={handleSubmit}
required
autoFocus
fullWidth
value={name}
onChange={handleChange}
error={isError}
id="user-name"
label="Name"
type="text"
isError={isError}
isStorageAllowed={isStorageAllowed}
storagePermissionLabel="Allow local username storage"
onStorageAllowanceChange={(event) => {
handleAllowanceChange(event.target.checked);
}}
NearW marked this conversation as resolved.
Show resolved Hide resolved
/>
</DialogContent>
<DialogActions>
Expand Down
21 changes: 20 additions & 1 deletion packages/frontend/src/common/utils/localStorage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const userNameKey = "userName";
const usernameStorePermissionKey = "userAllowsNameStorage";

function setUserName(userName: string) {
localStorage.setItem(userNameKey, userName);
Expand All @@ -8,4 +9,22 @@ function getUserName() {
return localStorage.getItem(userNameKey) ?? "";
}

export const LocalStorage = { setUserName, getUserName };
function removeUserName() {
localStorage.removeItem(userNameKey);
}

function setNameStorePermission(permission: boolean) {
localStorage.setItem(usernameStorePermissionKey, String(permission));
}

function getNameStorePermission(): boolean {
const value = localStorage.getItem(usernameStorePermissionKey);
return value === "true";
}
export const LocalStorage = {
NearW marked this conversation as resolved.
Show resolved Hide resolved
setUserName,
getUserName,
removeUserName,
setNameStorePermission,
getNameStorePermission,
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import { generateId } from "../../../common/utils/generateId";
import { TextInput } from "../../../common/components/TextInput";
import { useValidatedTextInput } from "../../../common/hooks/useValidatedTextInput";
import { useRoomContext } from "../../../common/context/RoomContext";
import { LocalStorage } from "../../../common/utils/localStorage";
import { useLocalStorage } from "../../../common/hooks/useLocalStorage";
import { CallToActionButton } from "../../../common/components/buttons/CallToActionButton";
import { useDialog } from "../../../common/hooks/useDialog";
import { useRedirect } from "../../../common/hooks/useRedirect";
import UserNameInputField from "./UsernameInputField";
import useLocalStorageName from "../../hooks/useLocalStorageName";

export function CreateRetroSessionDialog() {
const { isOpen, closeDialog } = useDialog(true);
Expand All @@ -50,14 +50,13 @@ export function CreateRetroSessionDialog() {
const { retroState, handleChangeRetroFormat, handleSetRetroState, handleJoinSession } =
useRetroContext();
const { user, setUser } = useUserContext();
const { isStorageAllowed, trySavingNameLocally, handleAllowanceChange } = useLocalStorageName({
setName,
});
const { setRoomId } = useRoomContext();
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));

useLocalStorage(() => {
setName(LocalStorage.getUserName());
});

function handleClose() {
setName("");
setTitle("");
Expand All @@ -82,7 +81,7 @@ export function CreateRetroSessionDialog() {
setRoomId(roomId);
handleSetRetroState({ ...retroState, title });
setUser(newUser);
LocalStorage.setUserName(name);
trySavingNameLocally(name);
handleJoinSession(newUser);
handleChangeRetroFormat(format);
redirectToRoom(roomId);
Expand All @@ -100,19 +99,21 @@ export function CreateRetroSessionDialog() {
<DialogTitle id="form-dialog-create-retro">Create Retro Session</DialogTitle>
<DialogContent sx={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
<Box>
<DialogContentText>Please enter your name</DialogContentText>
<TextInput
value={name}
<UserNameInputField
userName={name}
label="Please enter your name"
onSubmit={handleSubmit}
onChange={handleNameChange}
error={isNameError}
id="user-name"
label="Username"
autoFocus
NearW marked this conversation as resolved.
Show resolved Hide resolved
isError={isNameError}
isStorageAllowed={isStorageAllowed}
storagePermissionLabel="Allow local username storage"
NearW marked this conversation as resolved.
Show resolved Hide resolved
onStorageAllowanceChange={(event) => {
handleAllowanceChange(event.target.checked);
}}
NearW marked this conversation as resolved.
Show resolved Hide resolved
/>
</Box>
<Box>
<DialogContentText>Please provide your name for this session</DialogContentText>
<DialogContentText>Please provide a name for this session</DialogContentText>
<TextInput
value={title}
onSubmit={handleSubmit}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Checkbox, DialogContentText, FormControlLabel, Tooltip } from "@mui/material";
import { TextInput } from "../../../common/components/TextInput";
import React from "react";

interface UserNameInputFieldProps {
userName: string;
label: string;
onSubmit: () => void;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
isError: boolean;
storagePermissionLabel: string;
isStorageAllowed: boolean;
onStorageAllowanceChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
export default function UserNameInputField({
userName,
label,
onSubmit,
onChange,
isError,
isStorageAllowed,
storagePermissionLabel,
onStorageAllowanceChange,
}: UserNameInputFieldProps) {
return (
<>
<DialogContentText>{label}</DialogContentText>
<TextInput
value={userName}
onSubmit={onSubmit}
onChange={onChange}
error={isError}
id="user-name"
label="Username"
autoFocus
NearW marked this conversation as resolved.
Show resolved Hide resolved
/>
<Tooltip title="If checked the user name is saved in your local storage for future sessions. Your data stays always local and is not transmitted to any external service">
NearW marked this conversation as resolved.
Show resolved Hide resolved
<FormControlLabel
control={<Checkbox checked={isStorageAllowed} onChange={onStorageAllowanceChange} />}
label={storagePermissionLabel}
></FormControlLabel>
NearW marked this conversation as resolved.
Show resolved Hide resolved
</Tooltip>
</>
);
}
31 changes: 31 additions & 0 deletions packages/frontend/src/retro/hooks/useLocalStorageName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState } from "react";
import { LocalStorage } from "../../common/utils/localStorage";
import { useLocalStorage } from "../../common/hooks/useLocalStorage";

interface useLocalStorageNameProps {
setName: (name: string) => void;
}
export default function useLocalStorageName({ setName }: useLocalStorageNameProps) {
const [isStorageAllowed, setIsStorageAllowed] = useState(false);

useLocalStorage(() => {
setName(LocalStorage.getUserName());
setIsStorageAllowed(LocalStorage.getNameStorePermission());
});

function trySavingNameLocally(name: string) {
if (isStorageAllowed) {
LocalStorage.setUserName(name);
}
}

function handleAllowanceChange(isAllowed: boolean) {
if (!isAllowed) {
LocalStorage.removeUserName();
}
LocalStorage.setNameStorePermission(isAllowed);
setIsStorageAllowed(isAllowed);
}

return { isStorageAllowed, trySavingNameLocally, handleAllowanceChange };
}