@tumaet/prompt-shared-state 1.0.10 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -96
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,104 +1,202 @@
|
|
|
1
|
-
# prompt-shared-state
|
|
2
|
-
A shared library for the **AET Prompt2** system that provides common interfaces and state management (via [Zustand](https://github.com/pmndrs/zustand)) across multiple microfrontends.
|
|
1
|
+
# prompt-shared-state
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
The **prompt-shared-state** package is designed to help multiple microfrontends share:
|
|
6
|
-
- **Data** and **state** through a global [Zustand](https://github.com/pmndrs/zustand) store.
|
|
7
|
-
- **Common TypeScript interfaces** for consistent data modeling
|
|
3
|
+
A shared library for the **AET Prompt** system that provides common TypeScript interfaces and state management (via [Zustand](https://github.com/pmndrs/zustand)) across multiple microfrontends.
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
## Overview
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
- **Shared Interfaces**: Commonly used interfaces that can be referenced by any microfrontend, ensuring a single source of truth for data structures. These shall also reflect the data structures used by the core API.
|
|
13
|
-
- **Global State Management**: A single Zustand store instance shared across microfrontends.
|
|
14
|
-
- **Easy Integration**: Works seamlessly with Module Federation (Webpack 5), Yarn, and npm.
|
|
7
|
+
The **prompt-shared-state** package ensures that all microfrontends share:
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
- **Global state** through Zustand stores for authentication, course management, and more
|
|
10
|
+
- **Common TypeScript interfaces** for consistent data modeling that mirrors the core API
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
# Using Yarn
|
|
21
|
-
yarn add @tumaet/prompt-shared-state
|
|
12
|
+
By using this library, all microfrontends reference the same store instances and type definitions, eliminating state inconsistencies and data model duplication.
|
|
22
13
|
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Using Yarn
|
|
18
|
+
yarn add @tumaet/prompt-shared-state
|
|
19
|
+
|
|
20
|
+
# Using npm
|
|
21
|
+
npm install @tumaet/prompt-shared-state
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Zustand Stores
|
|
27
|
+
|
|
28
|
+
### useAuthStore
|
|
29
|
+
|
|
30
|
+
Manages authentication state and user permissions.
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { useAuthStore } from '@tumaet/prompt-shared-state'
|
|
34
|
+
|
|
35
|
+
function MyComponent() {
|
|
36
|
+
const { user, permissions, setUser, logout } = useAuthStore()
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div>
|
|
40
|
+
<p>Logged in as: {user?.firstName} {user?.lastName}</p>
|
|
41
|
+
<button onClick={() => logout()}>Log out</button>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**State & Actions:**
|
|
48
|
+
|
|
49
|
+
| Name | Type | Description |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `user` | `User \| undefined` | The currently authenticated user |
|
|
52
|
+
| `permissions` | `string[]` | List of permission strings for the current user |
|
|
53
|
+
| `setUser(user)` | `(user: User) => void` | Set the authenticated user |
|
|
54
|
+
| `clearUser()` | `() => void` | Clear the current user |
|
|
55
|
+
| `setPermissions(permissions)` | `(permissions: string[]) => void` | Set user permissions |
|
|
56
|
+
| `clearPermissions()` | `() => void` | Clear all permissions |
|
|
57
|
+
| `logout(redirectUri?)` | `(redirectUri?: string) => void` | Log out and optionally redirect |
|
|
58
|
+
| `setLogoutFunction(fn)` | `(logoutFunction: (redirectUri?: string) => void) => void` | Register the logout handler |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### useCourseStore
|
|
63
|
+
|
|
64
|
+
Manages course data and the currently selected course. Course selection is persisted to localStorage.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useCourseStore } from '@tumaet/prompt-shared-state'
|
|
68
|
+
|
|
69
|
+
function CourseSelector() {
|
|
70
|
+
const { courses, getSelectedCourseID, setSelectedCourseID } = useCourseStore()
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<select
|
|
74
|
+
value={getSelectedCourseID() ?? ''}
|
|
75
|
+
onChange={(e) => setSelectedCourseID(e.target.value)}
|
|
76
|
+
>
|
|
77
|
+
{courses.map((course) => (
|
|
78
|
+
<option key={course.id} value={course.id}>
|
|
79
|
+
{course.name}
|
|
80
|
+
</option>
|
|
81
|
+
))}
|
|
82
|
+
</select>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**State & Actions:**
|
|
88
|
+
|
|
89
|
+
| Name | Type | Description |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `courses` | `Course[]` | All available courses |
|
|
92
|
+
| `ownCourseIDs` | `string[]` | IDs of courses the user is enrolled in |
|
|
93
|
+
| `setCourses(courses)` | `(courses: Course[]) => void` | Set the full course list |
|
|
94
|
+
| `setOwnCourseIDs(ids)` | `(ids: string[]) => void` | Set IDs of the user's own courses |
|
|
95
|
+
| `getSelectedCourseID()` | `() => string \| null` | Get the currently selected course ID |
|
|
96
|
+
| `setSelectedCourseID(id)` | `(id: string) => void` | Select a course (persisted to localStorage) |
|
|
97
|
+
| `removeSelectedCourseID()` | `() => void` | Clear the selected course |
|
|
98
|
+
| `isStudentOfCourse(id)` | `(id: string) => boolean` | Check if the user is a student in a course |
|
|
99
|
+
| `updateCourse(id, patch)` | `(id: string, patch: Partial<Course>) => void` | Partially update a course |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## TypeScript Interfaces
|
|
104
|
+
|
|
105
|
+
All interfaces are exported from the package root and organized into categories:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import {
|
|
109
|
+
Course,
|
|
110
|
+
Student,
|
|
111
|
+
User,
|
|
112
|
+
CoursePhaseWithMetaData,
|
|
113
|
+
PassStatus,
|
|
114
|
+
Role,
|
|
115
|
+
ScoreLevel,
|
|
116
|
+
} from '@tumaet/prompt-shared-state'
|
|
25
117
|
```
|
|
26
118
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
### Available Interfaces
|
|
120
|
+
|
|
121
|
+
| Category | Key Exports | Description |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| **Course** | `Course`, `UpdateCourse`, `CourseType` | Course data and operations |
|
|
124
|
+
| **Course Phase** | `CoursePhaseWithMetaData`, `CoursePhaseWithType`, `CreateCoursePhase`, `UpdateCoursePhase` | Course phase data and operations |
|
|
125
|
+
| **Course Phase Type** | `CoursePhaseType`, `CoursePhaseTypeMetaDataItem` | Phase type metadata |
|
|
126
|
+
| **Course Phase Participation** | `CoursePhaseParticipationWithStudent`, `CoursePhaseParticipationsWithResolution`, `UpdateCoursePhaseParticipation`, `UpdateCoursePhaseParticipationStatus` | Student participation in phases |
|
|
127
|
+
| **Student** | `Student`, `Gender`, `StudyDegree` | Student profile data |
|
|
128
|
+
| **User** | `User` | Authenticated user data |
|
|
129
|
+
| **Person** | `Person` | Base person interface |
|
|
130
|
+
| **Roles** | `Role`, `getPermissionString` | Role enum and permission utilities |
|
|
131
|
+
| **Assessment** | `ScoreLevel`, `mapScoreLevelToNumber`, `mapNumberToScoreLevel` | Assessment score levels and mapping |
|
|
132
|
+
| **Mailing** | `CourseMailingSettings`, `CoursePhaseMailingConfigData`, `MailingReport`, `SendStatusMail` | Email configuration and reporting |
|
|
133
|
+
| **Application** | `ExportedApplicationAnswer` | Application submission data |
|
|
134
|
+
| **Team** | `Team` | Team definitions |
|
|
135
|
+
|
|
136
|
+
### Score Levels
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { ScoreLevel, mapScoreLevelToNumber, mapNumberToScoreLevel } from '@tumaet/prompt-shared-state'
|
|
140
|
+
|
|
141
|
+
// Enum values: VeryGood, Good, Ok, Bad, VeryBad
|
|
142
|
+
const level = ScoreLevel.Good
|
|
143
|
+
const numeric = mapScoreLevelToNumber(ScoreLevel.Good) // → number
|
|
144
|
+
const back = mapNumberToScoreLevel(numeric) // → ScoreLevel
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Roles
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { Role } from '@tumaet/prompt-shared-state'
|
|
151
|
+
|
|
152
|
+
// Enum members: PROMPT_ADMIN, PROMPT_LECTURER, COURSE_LECTURER, COURSE_EDITOR, COURSE_STUDENT
|
|
153
|
+
if (user.role === Role.PROMPT_ADMIN) {
|
|
154
|
+
// show admin UI
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Module Federation Configuration
|
|
161
|
+
|
|
162
|
+
For the state to be truly shared across all microfrontends, configure **Module Federation** to treat `@tumaet/prompt-shared-state` as a singleton:
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
new ModuleFederationPlugin({
|
|
166
|
+
name: 'your-module',
|
|
167
|
+
shared: {
|
|
168
|
+
'@tumaet/prompt-shared-state': {
|
|
169
|
+
singleton: true,
|
|
170
|
+
requiredVersion: deps['@tumaet/prompt-shared-state'],
|
|
171
|
+
},
|
|
172
|
+
// ...other shared dependencies
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
This ensures there is only **one** instance of the shared state library at runtime. Without this, each microfrontend would have its own store and state changes would not propagate across apps.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Best Practices
|
|
182
|
+
|
|
183
|
+
1. **Store only truly shared data** — Only add state to Zustand stores that needs to be accessed by multiple microfrontends. Keep module-local state in the microfrontend itself.
|
|
184
|
+
2. **Keep interfaces organized** — Only place interfaces in this package if they are used across multiple microfrontends. Module-specific interfaces should stay in that module.
|
|
185
|
+
3. **Synchronize versions** — All microfrontends should use the same version of this package to avoid type and runtime incompatibilities.
|
|
186
|
+
4. **Avoid overexposing sensitive state** — Think carefully before storing security-sensitive data in a globally shared store.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Contributing
|
|
191
|
+
|
|
192
|
+
Contribute changes by opening a pull request in this repository. Once merged, create a GitHub Release for the version you want to publish.
|
|
193
|
+
|
|
194
|
+
### Versioning & Publishing
|
|
195
|
+
|
|
196
|
+
Publishing is triggered by creating a **GitHub Release**. The steps are:
|
|
197
|
+
|
|
198
|
+
1. Update the version in `package.json` so it matches the intended release tag.
|
|
199
|
+
2. Create a GitHub Release with the tag `v{version}` (for example, `v1.2.3`).
|
|
200
|
+
3. The publish workflow validates the tag/version match, builds the package, and publishes it to npm.
|
|
201
|
+
|
|
202
|
+
This package is published independently from `@tumaet/prompt-ui-components`.
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tumaet/prompt-shared-state",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
|
-
"url": "git+https://github.com/
|
|
6
|
+
"url": "git+https://github.com/prompt-edu/prompt-shared-state.git"
|
|
7
7
|
},
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"module": "./dist/index.js",
|
|
@@ -21,19 +21,19 @@
|
|
|
21
21
|
"build": "yarn build:esm",
|
|
22
22
|
"lint": "eslint \"**/*.{js,jsx,ts,tsx}\""
|
|
23
23
|
},
|
|
24
|
-
"packageManager": "yarn@4.
|
|
24
|
+
"packageManager": "yarn@4.14.1",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"typescript": "^5.9.3",
|
|
27
27
|
"zustand": "^5.0.12"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@eslint/
|
|
31
|
-
"@typescript-eslint/
|
|
32
|
-
"
|
|
33
|
-
"eslint": "^10.1.0",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^8.59.0",
|
|
31
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
32
|
+
"eslint": "^10.2.1",
|
|
34
33
|
"eslint-plugin-prettier": "^5.5.5",
|
|
35
34
|
"eslint-plugin-react": "^7.37.5",
|
|
36
|
-
"eslint-plugin-react-hooks": "^7.
|
|
37
|
-
"
|
|
35
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
36
|
+
"globals": "^17.5.0",
|
|
37
|
+
"prettier": "^3.8.3"
|
|
38
38
|
}
|
|
39
39
|
}
|