@@ -6,30 +6,35 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
66import { UmbContextBase } from '@umbraco-cms/backoffice/class-api' ;
77import type { UmbApi } from '@umbraco-cms/backoffice/extension-api' ;
88import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth' ;
9+ import { UmbReadOnlyStateManager } from '@umbraco-cms/backoffice/utils' ;
10+ import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user' ;
911
1012// TODO: Make a store for the App Languages.
1113// TODO: Implement default language end-point, in progress at backend team, so we can avoid getting all languages.
1214export class UmbAppLanguageContext extends UmbContextBase < UmbAppLanguageContext > implements UmbApi {
13- #languageCollectionRepository: UmbLanguageCollectionRepository ;
1415 #languages = new UmbArrayState < UmbLanguageDetailModel > ( [ ] , ( x ) => x . unique ) ;
15- moreThanOneLanguage = this . #languages. asObservablePart ( ( x ) => x . length > 1 ) ;
1616
1717 #appLanguage = new UmbObjectState < UmbLanguageDetailModel | undefined > ( undefined ) ;
18- appLanguage = this . #appLanguage. asObservable ( ) ;
18+ public readonly appLanguage = this . #appLanguage. asObservable ( ) ;
19+ public readonly appLanguageCulture = this . #appLanguage. asObservablePart ( ( x ) => x ?. unique ) ;
1920
20- appLanguageCulture = this . #appLanguage . asObservablePart ( ( x ) => x ?. unique ) ;
21+ public readonly appLanguageReadOnlyState = new UmbReadOnlyStateManager ( this ) ;
2122
22- appDefaultLanguage = createObservablePart ( this . #languages. asObservable ( ) , ( languages ) =>
23+ public readonly appDefaultLanguage = createObservablePart ( this . #languages. asObservable ( ) , ( languages ) =>
2324 languages . find ( ( language ) => language . isDefault ) ,
2425 ) ;
2526
26- getAppCulture ( ) {
27- return this . #appLanguage. getValue ( ) ?. unique ;
28- }
27+ public readonly moreThanOneLanguage = this . #languages. asObservablePart ( ( x ) => x . length > 1 ) ;
28+
29+ #languageCollectionRepository = new UmbLanguageCollectionRepository ( this ) ;
30+ #currentUserAllowedLanguages: Array < string > = [ ] ;
31+ #currentUserHasAccessToAllLanguages = false ;
32+
33+ #readOnlyStateIdentifier = 'UMB_LANGUAGE_PERMISSION_' ;
34+ #localStorageKey = 'umb:appLanguage' ;
2935
3036 constructor ( host : UmbControllerHost ) {
3137 super ( host , UMB_APP_LANGUAGE_CONTEXT ) ;
32- this . #languageCollectionRepository = new UmbLanguageCollectionRepository ( this ) ;
3338
3439 // TODO: We need to ensure this request is called every time the user logs in, but this should be done somewhere across the app and not here [JOV]
3540 this . consumeContext ( UMB_AUTH_CONTEXT , ( authContext ) => {
@@ -38,12 +43,46 @@ export class UmbAppLanguageContext extends UmbContextBase<UmbAppLanguageContext>
3843 this . #observeLanguages( ) ;
3944 } ) ;
4045 } ) ;
46+
47+ this . consumeContext ( UMB_CURRENT_USER_CONTEXT , ( context ) => {
48+ this . observe ( context . languages , ( languages ) => {
49+ this . #currentUserAllowedLanguages = languages || [ ] ;
50+ this . #setIsReadOnly( ) ;
51+ } ) ;
52+
53+ this . observe ( context . hasAccessToAllLanguages , ( hasAccessToAllLanguages ) => {
54+ this . #currentUserHasAccessToAllLanguages = hasAccessToAllLanguages || false ;
55+ this . #setIsReadOnly( ) ;
56+ } ) ;
57+ } ) ;
58+ }
59+
60+ getAppCulture ( ) {
61+ return this . #appLanguage. getValue ( ) ?. unique ;
4162 }
4263
4364 setLanguage ( unique : string ) {
44- const languages = this . #languages. getValue ( ) ;
45- const language = languages . find ( ( x ) => x . unique === unique ) ;
65+ // clear the previous read-only state
66+ const appLanguage = this . #appLanguage. getValue ( ) ;
67+ if ( appLanguage ?. unique ) {
68+ this . appLanguageReadOnlyState . removeState ( this . #readOnlyStateIdentifier + appLanguage . unique ) ;
69+ }
70+
71+ // find the language
72+ const language = this . #findLanguage( unique ) ;
73+
74+ if ( ! language ) {
75+ throw new Error ( `Language with unique ${ unique } not found` ) ;
76+ }
77+
78+ // set the new language
4679 this . #appLanguage. update ( language ) ;
80+
81+ // store the new language in local storage
82+ localStorage . setItem ( this . #localStorageKey, language ?. unique ) ;
83+
84+ // set the new read-only state
85+ this . #setIsReadOnly( ) ;
4786 }
4887
4988 async #observeLanguages( ) {
@@ -61,13 +100,55 @@ export class UmbAppLanguageContext extends UmbContextBase<UmbAppLanguageContext>
61100 }
62101
63102 #initAppLanguage( ) {
103+ // get the selected language from local storage
104+ const uniqueFromLocalStorage = localStorage . getItem ( this . #localStorageKey) ;
105+
106+ if ( uniqueFromLocalStorage ) {
107+ const language = this . #findLanguage( uniqueFromLocalStorage ) ;
108+ if ( language ) {
109+ this . setLanguage ( language . unique ) ;
110+ return ;
111+ }
112+ }
113+
64114 const defaultLanguage = this . #languages. getValue ( ) . find ( ( x ) => x . isDefault ) ;
65115 // TODO: do we always have a default language?
66116 // do we always get the default language on the first request, or could it be on page 2?
67117 // in that case do we then need an endpoint to get the default language?
68118 if ( ! defaultLanguage ?. unique ) return ;
69119 this . setLanguage ( defaultLanguage . unique ) ;
70120 }
121+
122+ #findLanguage( unique : string ) {
123+ return this . #languages. getValue ( ) . find ( ( x ) => x . unique === unique ) ;
124+ }
125+
126+ #setIsReadOnly( ) {
127+ const appLanguage = this . #appLanguage. getValue ( ) ;
128+
129+ if ( ! appLanguage ) {
130+ this . appLanguageReadOnlyState . clear ( ) ;
131+ return ;
132+ }
133+
134+ const unique = this . #readOnlyStateIdentifier + appLanguage . unique ;
135+ this . appLanguageReadOnlyState . removeState ( unique ) ;
136+
137+ if ( this . #currentUserHasAccessToAllLanguages) {
138+ return ;
139+ }
140+
141+ const isReadOnly = ! this . #currentUserAllowedLanguages. includes ( appLanguage . unique ) ;
142+
143+ if ( isReadOnly ) {
144+ const readOnlyState = {
145+ unique,
146+ message : 'You do not have permission to edit to this culture' ,
147+ } ;
148+
149+ this . appLanguageReadOnlyState . addState ( readOnlyState ) ;
150+ }
151+ }
71152}
72153
73154// Default export to enable this as a globalContext extension js:
0 commit comments