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

Feature/interface theme #624

Merged
merged 19 commits into from
Apr 21, 2022
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4d65b5f
Web:Common:Store: remove change theme method from settings store
TimofeyBoyko Apr 18, 2022
797c96a
Web:Common:Store: add new theme key 'system' for setTheme method
TimofeyBoyko Apr 18, 2022
d9dec59
Web:Common:Store: change default theme to base
TimofeyBoyko Apr 18, 2022
f14712d
Web:Studio:Shell: update check theme method
TimofeyBoyko Apr 18, 2022
4f61253
Web:Common:SettingsStore: add theme-key to local storage when set the…
TimofeyBoyko Apr 18, 2022
ca9e132
Web: remove key 'DarkMode' in EU and RU locales
TimofeyBoyko Apr 18, 2022
8306b01
Web:People: add new keys 'DarkTheme', 'InterfaceTheme', 'LightTheme',…
TimofeyBoyko Apr 18, 2022
f927aaa
Web:Studio: add check theme key from local storage
TimofeyBoyko Apr 18, 2022
8eb578a
Web:People:Profile: add interface-theme section into user profile
TimofeyBoyko Apr 18, 2022
d6fcc35
Merge branch 'feature/virtual-rooms-1.2' into feature/interface-theme
TimofeyBoyko Apr 18, 2022
216ae27
Merge branch 'feature/virtual-rooms-1.2' into feature/interface-theme
TimofeyBoyko Apr 20, 2022
b1b7806
Web:Common:Constants: add new constant 'ThemeKeys'
TimofeyBoyko Apr 21, 2022
8125631
Web:Common:Api: add new api method 'changeTheme'
TimofeyBoyko Apr 21, 2022
01a0402
Web:Common:Store: add new method 'changeTheme' for user store
TimofeyBoyko Apr 21, 2022
dfe16d0
Web:Common:Store: update 'setTheme' method for settingsStore
TimofeyBoyko Apr 21, 2022
811c4d1
Web:People:Profile: add 'onChangeTheme' method and update interface t…
TimofeyBoyko Apr 21, 2022
e5ce29f
Web:Studio:Shell: update theme when current user theme changed
TimofeyBoyko Apr 21, 2022
414976c
Merge branch 'feature/virtual-rooms-1.2' into feature/interface-theme
TimofeyBoyko Apr 21, 2022
78944a4
Merge branch 'feature/virtual-rooms-1.2' into feature/interface-theme
AlexeySafronov Apr 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/asc-web-common/api/people/index.js
Original file line number Diff line number Diff line change
@@ -303,3 +303,13 @@ export function getSelectorUserList() {
url: "/people/filter.json?fields=id,displayName,groups",
});
}

export function changeTheme(key) {
const data = { Theme: key };

return request({
method: "put",
url: `/people/theme.json`,
data,
});
}
13 changes: 13 additions & 0 deletions packages/asc-web-common/constants/index.js
Original file line number Diff line number Diff line change
@@ -199,3 +199,16 @@ export const FileStatus = Object.freeze({
export const TenantStatus = Object.freeze({
PortalRestore: 4,
});

/**
* Enum for theme keys.
* @readonly
*/
export const ThemeKeys = Object.freeze({
Base: "0",
BaseStr: "Base",
Dark: "1",
DarkStr: "Dark",
System: "2",
SystemStr: "System",
});
37 changes: 22 additions & 15 deletions packages/asc-web-common/store/SettingsStore.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import api from "../api";
import { LANGUAGE, TenantStatus } from "../constants";
import { combineUrl } from "../utils";
import FirebaseHelper from "../utils/firebase";
import { AppServerConfig } from "../constants";
import { AppServerConfig, ThemeKeys } from "../constants";
import { version } from "../package.json";
import SocketIOHelper from "../utils/socket";

@@ -26,9 +26,7 @@ class SettingsStore {
currentProductId = "";
culture = "en";
cultures = [];
theme = !!localStorage.getItem("theme")
? themes[localStorage.getItem("theme")]
: Base;
theme = Base;
trustedDomains = [];
trustedDomainsType = 0;
timezone = "UTC";
@@ -440,19 +438,28 @@ class SettingsStore {
this.buildVersionInfo.documentServer = "6.4.1";
};

changeTheme = () => {
const currentTheme =
JSON.stringify(this.theme) === JSON.stringify(Base) ? Dark : Base;
localStorage.setItem(
"theme",
JSON.stringify(this.theme) === JSON.stringify(Base) ? "Dark" : "Base"
);
this.theme = currentTheme;
};
setTheme = (key) => {
let theme = null;
switch (key) {
case ThemeKeys.Base:
case ThemeKeys.BaseStr:
theme = ThemeKeys.BaseStr;
break;
case ThemeKeys.Dark:
case ThemeKeys.DarkStr:
theme = ThemeKeys.DarkStr;
break;
case ThemeKeys.System:
case ThemeKeys.SystemStr:
default:
theme =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? ThemeKeys.DarkStr
: ThemeKeys.BaseStr;
}

setTheme = (theme) => {
this.theme = themes[theme];
localStorage.setItem("theme", theme);
};

setMailDomainSettings = async (data) => {
12 changes: 12 additions & 0 deletions packages/asc-web-common/store/UserStore.js
Original file line number Diff line number Diff line change
@@ -48,6 +48,18 @@ class UserStore {
this.setIsLoading(false);
};

changeTheme = async (key) => {
this.setIsLoading(true);

const { theme } = await api.people.changeTheme(key);

this.user.theme = theme;

this.setIsLoading(false);

return theme;
};

setUserIsUpdate = (isUpdate) => {
//console.log("setUserIsUpdate");
this.userIsUpdate = isUpdate;
4 changes: 4 additions & 0 deletions products/ASC.People/Client/public/locales/en/Profile.json
Original file line number Diff line number Diff line change
@@ -3,11 +3,14 @@
"ChangesApplied": "Changes are applied",
"ContactInformation": "Contact Information",
"CountCodesRemaining": "codes remaining",
"DarkTheme": "Dark theme",
"Disconnect": "Disconnect",
"EditPhoto": "Edit photo",
"EditSubscriptionsBtn": "Edit subscriptions",
"EditUser": "Edit profile",
"InterfaceTheme": "Interface theme",
"InviteAgainLbl": "Invite again",
"LightTheme": "Light theme",
"LoginSettings": "Login settings",
"MessageEmailActivationInstuctionsSentOnEmail": "The email activation instructions have been sent to the <strong>{{ email }}</strong> email address",
"PhoneLbl": "Phone",
@@ -17,6 +20,7 @@
"Subscriptions": "Subscriptions",
"SubscriptionEmailTipsToggleLbl": "Email notification with tips and tricks",
"SubscriptionTurnOffToast": "You have been successfully unsubscribed from the the mailing list. <1>Subscribe again</1>",
"SystemTheme": "Use system theme",
"TfaLoginSettings": "Login settings",
"TwoFactorDescription": "Two-factor authentication via a code-generating app was enabled for all users by the admin."
}
4 changes: 4 additions & 0 deletions products/ASC.People/Client/public/locales/ru/Profile.json
Original file line number Diff line number Diff line change
@@ -3,18 +3,22 @@
"ChangesApplied": "Изменения успешно применены",
"ContactInformation": "Контактные данные",
"CountCodesRemaining": "оставшиеся коды",
"DarkTheme": "Тёмная тема",
"Disconnect": "Отключить",
"EditPhoto": "Изменить фотографию",
"EditSubscriptionsBtn": "Изменить подписки",
"EditUser": "Редактировать",
"InterfaceTheme": "Тема интерфейса",
"InviteAgainLbl": "Активировать адрес email ещё раз",
"LightTheme": "Светлая тема",
"LoginSettings": "Вход через социальные сети",
"MessageEmailActivationInstuctionsSentOnEmail": "Инструкция по активации почты пользователя была отправлена по адресу <strong>{{ email }}</strong>",
"PhoneLbl": "Основной телефон",
"ProviderSuccessfullyConnected": "Провайдер успешно подключен",
"ProviderSuccessfullyDisconnected": "Провайдер успешно отключен",
"ShowBackupCodes": "Показать резервные коды",
"Subscriptions": "Подписки",
"SystemTheme": "Использовать тему системы",
"TfaLoginSettings": "Настройки входа",
"TwoFactorDescription": "Двухфакторная аутентификация с помощью приложения для генерации кодов включена администратором для всех пользователей."
}
70 changes: 64 additions & 6 deletions products/ASC.People/Client/src/pages/Profile/Section/Body/index.js
Original file line number Diff line number Diff line change
@@ -26,8 +26,16 @@ import {
getUserRole,
} from "../../../../helpers/people-helpers";
import config from "../../../../../package.json";
import { AppServerConfig, providersData } from "@appserver/common/constants";
import { unlinkOAuth, linkOAuth } from "@appserver/common/api/people";
import {
AppServerConfig,
providersData,
ThemeKeys,
} from "@appserver/common/constants";
import {
unlinkOAuth,
linkOAuth,
changeTheme,
} from "@appserver/common/api/people";
import { getAuthProviders } from "@appserver/common/api/settings";
import { Trans, useTranslation } from "react-i18next";
import {
@@ -37,6 +45,7 @@ import {

import Loaders from "@appserver/common/components/Loaders";
import withLoader from "../../../../HOCs/withLoader";
import RadioButtonGroup from "@appserver/components/radio-button-group";

const ProfileWrapper = styled.div`
display: flex;
@@ -344,6 +353,18 @@ class SectionBodyContent extends React.PureComponent {
this.props.changeEmailSubscription(checked);
};

onChangeTheme = async (e) => {
const { setIsLoading, changeTheme, setTheme } = this.props;

const value = e.currentTarget.value;

setIsLoading(true);

await changeTheme(value);

setIsLoading(false);
};

render() {
const { resetAppDialogVisible, backupCodesDialogVisible, tfa } = this.state;
const {
@@ -359,6 +380,8 @@ class SectionBodyContent extends React.PureComponent {
personal,
tipsSubscription,
theme,
setTheme,
selectedTheme,
} = this.props;
const contacts = profile.contacts && getUserContacts(profile.contacts);
const role = getUserRole(profile);
@@ -483,8 +506,27 @@ class SectionBodyContent extends React.PureComponent {
</ToggleWrapper>
)}

{profile.notes && (
{isSelf && (
<ToggleWrapper>
<ToggleContent label={t("InterfaceTheme")} isOpen={true}>
<RadioButtonGroup
orientation={"vertical"}
name={"interface-theme"}
options={[
{ value: ThemeKeys.SystemStr, label: t("SystemTheme") },
{ value: ThemeKeys.BaseStr, label: t("LightTheme") },
{ value: ThemeKeys.DarkStr, label: t("DarkTheme") },
]}
onClick={this.onChangeTheme}
selected={selectedTheme}
spacing={"10px"}
/>
</ToggleContent>
</ToggleWrapper>
)}

{profile.notes && (
<ToggleWrapper isContacts={true}>
<ToggleContent label={t("Translations:Comments")} isOpen={true}>
<Text className="profile-comments" as="span">
{profile.notes}
@@ -535,9 +577,21 @@ class SectionBodyContent extends React.PureComponent {
export default withRouter(
inject(({ auth, peopleStore }) => {
const { isAdmin, userStore, settingsStore, tfaStore } = auth;
const { user: viewer } = userStore;
const { isTabletView, getOAuthToken, getLoginLink, theme } = settingsStore;
const { targetUserStore, avatarEditorStore, usersStore } = peopleStore;
const { user: viewer, changeTheme } = userStore;

const {
isTabletView,
getOAuthToken,
getLoginLink,
theme,
setTheme,
} = settingsStore;
const {
targetUserStore,
avatarEditorStore,
usersStore,
loadingStore,
} = peopleStore;
const {
targetUser: profile,
isMe: isSelf,
@@ -579,6 +633,10 @@ export default withRouter(
changeEmailSubscription,
tipsSubscription,
theme,
setTheme,
changeTheme,
selectedTheme: viewer.theme,
setIsLoading: loadingStore.setIsLoading,
};
})(
observer(
1 change: 0 additions & 1 deletion public/locales/en/Common.json
Original file line number Diff line number Diff line change
@@ -52,7 +52,6 @@
"Culture_uk": "Ukrainian (Ukraine)",
"Culture_vi": "Vietnamese (Vietnam)",
"Culture_zh-CN": "Chinese (Simplified, PRC)",
"DarkMode": "Dark mode",
"Duplicate": "Create a copy",
"Delete": "Delete",
"Department": "Department",
1 change: 0 additions & 1 deletion public/locales/ru/Common.json
Original file line number Diff line number Diff line change
@@ -52,7 +52,6 @@
"Culture_uk": "Украинский (Украина)",
"Culture_vi": "Вьетнамский (Вьетнам)",
"Culture_zh-CN": "Китайский (упрощенный, КНР)",
"DarkMode": "Тёмная тема",
"Duplicate": "Создать копию",
"Delete": "Удалить",
"Department": "Отдел",
23 changes: 6 additions & 17 deletions web/ASC.Web.Client/src/Shell.jsx
Original file line number Diff line number Diff line change
@@ -175,21 +175,6 @@ const InvalidRoute = (props) => (

const RedirectToHome = () => <Redirect to={PROXY_HOMEPAGE_URL} />;

const checkTheme = () => {
const theme = localStorage.getItem("theme");

if (theme) return theme;

if (
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
) {
return "Dark";
}

return "Base";
};

const Shell = ({ items = [], page = "home", ...rest }) => {
const {
isLoaded,
@@ -206,6 +191,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
setMaintenanceExist,
roomsMode,
setSnackbarExist,
userTheme,
} = rest;

useEffect(() => {
@@ -431,8 +417,8 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
}, [page]);

useEffect(() => {
setTheme(checkTheme());
}, []);
if (userTheme) setTheme(userTheme);
}, [userTheme]);

const pathname = window.location.pathname.toLowerCase();
const isEditor = pathname.indexOf("doceditor") !== -1;
@@ -567,6 +553,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {

const ShellWrapper = inject(({ auth, backup }) => {
const { init, isLoaded, settingsStore, setProductVersion, language } = auth;

const {
personal,
roomsMode,
@@ -605,11 +592,13 @@ const ShellWrapper = inject(({ auth, backup }) => {
setTheme,
roomsMode,
setSnackbarExist,
userTheme: auth?.userStore?.user?.theme,
};
})(observer(Shell));

const ThemeProviderWrapper = inject(({ auth }) => {
const { settingsStore } = auth;

return { theme: settingsStore.theme };
})(observer(ThemeProvider));