Add ability to easily create unions of action types
This commit is contained in:
parent
65d14df812
commit
eedd57c527
49
package-lock.json
generated
49
package-lock.json
generated
@ -27,6 +27,7 @@
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.2.0.tgz",
|
||||
"integrity": "sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.12.0"
|
||||
}
|
||||
@ -788,13 +789,7 @@
|
||||
"dev": true
|
||||
},
|
||||
"@rondo/client": {
|
||||
"version": "file:packages/client",
|
||||
"requires": {
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-redux": "^6.0.0",
|
||||
"redux": "^4.0.1"
|
||||
}
|
||||
"version": "file:packages/client"
|
||||
},
|
||||
"@rondo/common": {
|
||||
"version": "file:packages/common"
|
||||
@ -1489,6 +1484,16 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.3.0",
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
@ -4887,6 +4892,15 @@
|
||||
"readable-stream": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz",
|
||||
"integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "=3.1.0"
|
||||
}
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
@ -6134,6 +6148,7 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.2.1.tgz",
|
||||
"integrity": "sha512-TFsu3TV3YLY+zFTZDrN8L2DTFanObwmBLpWvJs1qfUuEQ5bTAdFcwfx2T/bsCXfM9QHSLvjfP+nihEl0yvozxw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"react-is": "^16.3.2"
|
||||
}
|
||||
@ -6456,6 +6471,7 @@
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
@ -8135,7 +8151,8 @@
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.12.1",
|
||||
@ -8652,6 +8669,7 @@
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
@ -10231,6 +10249,7 @@
|
||||
"version": "15.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
|
||||
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
@ -10458,6 +10477,7 @@
|
||||
"version": "16.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz",
|
||||
"integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@ -10469,6 +10489,7 @@
|
||||
"version": "16.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz",
|
||||
"integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@ -10479,12 +10500,14 @@
|
||||
"react-is": {
|
||||
"version": "16.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.7.0.tgz",
|
||||
"integrity": "sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g=="
|
||||
"integrity": "sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==",
|
||||
"dev": true
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-6.0.0.tgz",
|
||||
"integrity": "sha512-EmbC3uLl60pw2VqSSkj6HpZ6jTk12RMrwXMBdYtM6niq0MdEaRq9KYCwpJflkOZj349BLGQm1MI/JO1W96kLWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"hoist-non-react-statics": "^3.2.1",
|
||||
@ -10673,6 +10696,7 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz",
|
||||
"integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"symbol-observable": "^1.2.0"
|
||||
@ -10686,7 +10710,8 @@
|
||||
"regenerator-runtime": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
|
||||
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
|
||||
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==",
|
||||
"dev": true
|
||||
},
|
||||
"regex-cache": {
|
||||
"version": "0.4.4",
|
||||
@ -10979,6 +11004,7 @@
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz",
|
||||
"integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@ -11781,7 +11807,8 @@
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"symbol-tree": {
|
||||
"version": "3.2.2",
|
||||
|
||||
17
package.json
17
package.json
@ -1,4 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@rondo/client": "file:packages/client",
|
||||
"@rondo/common": "file:packages/common",
|
||||
"@rondo/server": "file:packages/server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^3.0.0",
|
||||
"@types/body-parser": "^1.17.0",
|
||||
@ -20,6 +25,11 @@
|
||||
"@types/std-mocks": "^1.0.0",
|
||||
"@types/supertest": "^2.0.7",
|
||||
"@types/uuid": "^3.4.4",
|
||||
"axios": "^0.18.0",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-redux": "^6.0.0",
|
||||
"redux": "^4.0.1",
|
||||
"browserify": "^16.2.3",
|
||||
"buildfile": "^1.2.17",
|
||||
"jest": "^23.6.0",
|
||||
@ -38,10 +48,5 @@
|
||||
"typescript-tslint-plugin": "^0.2.1",
|
||||
"watchify": "^3.11.0"
|
||||
},
|
||||
"name": "node",
|
||||
"dependencies": {
|
||||
"@rondo/client": "file:packages/client",
|
||||
"@rondo/common": "file:packages/common",
|
||||
"@rondo/server": "file:packages/server"
|
||||
}
|
||||
"name": "node"
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@rondo/client",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"peerDependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-redux": "^6.0.0",
|
||||
|
||||
19
packages/client/src/actions/ActionTypes.ts
Normal file
19
packages/client/src/actions/ActionTypes.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// Get the type of promise
|
||||
// https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||||
// section: Type inference in conditional types
|
||||
type Unpacked<T> = T extends Promise<infer U> ? U : T
|
||||
import {IAction} from './IAction'
|
||||
|
||||
// Also from TypeScript handbook:
|
||||
// https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||||
type FunctionProperties<T> = {
|
||||
[K in keyof T]: T[K] extends (...args: any[]) => IAction<any, string> ? {
|
||||
payload: Unpacked<ReturnType<T[K]>['payload']>,
|
||||
type: Unpacked<ReturnType<T[K]>['type']>,
|
||||
}: never
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/48305190/
|
||||
// Is there an automatic way to create a discriminated union for all interfaces
|
||||
// in a namespace?
|
||||
export type ActionTypes<T> = FunctionProperties<T>[keyof FunctionProperties<T>]
|
||||
7
packages/client/src/actions/IAction.ts
Normal file
7
packages/client/src/actions/IAction.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// Maybe this won't be necessary after this is merged:
|
||||
// https://github.com/Microsoft/TypeScript/pull/29478
|
||||
|
||||
export interface IAction<T, ActionType extends string> {
|
||||
payload: Promise<T> | T,
|
||||
type: ActionType
|
||||
}
|
||||
13
packages/client/src/actions/UnionType.ts
Normal file
13
packages/client/src/actions/UnionType.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// Get the type of promise
|
||||
// https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||||
// section: Type inference in conditional types
|
||||
type Unpacked<T> = T extends Promise<infer U> ? U : T
|
||||
|
||||
type FunctionProperties<T> = {
|
||||
[K in keyof T]: T[K] extends (...args: any[]) => any ? {
|
||||
payload: Unpacked<ReturnType<T[K]>['payload']>,
|
||||
type: Unpacked<ReturnType<T[K]>['type']>,
|
||||
}: never
|
||||
}
|
||||
|
||||
export type UnionType<T> = FunctionProperties<T>[keyof FunctionProperties<T>]
|
||||
39
packages/client/src/actions/UserActions.ts
Normal file
39
packages/client/src/actions/UserActions.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import {ActionTypes} from './ActionTypes'
|
||||
import {IAPIDef, ICredentials, IUser} from '@rondo/common'
|
||||
import {IHTTPClient} from '../http/IHTTPClient'
|
||||
|
||||
export enum UserActionKeys {
|
||||
USER_LOG_IN = 'USER_LOG_IN',
|
||||
USER_LOG_IN_FULFILLED = 'USER_LOG_IN_FULFILLED',
|
||||
USER_LOG_IN_REJECTED = 'USER_LOG_IN_REJECTED',
|
||||
|
||||
USER_LOG_OUT = 'USER_LOG_OUT',
|
||||
USER_LOG_OUT_FULFILLED = 'USER_LOG_OUT_FULFILLED',
|
||||
USER_LOG_OUT_REJECTED = 'USER_LOG_OUT_REJECTED',
|
||||
}
|
||||
|
||||
interface IAction<PayloadType, ActionType> {
|
||||
payload: Promise<PayloadType> | PayloadType,
|
||||
type: ActionType
|
||||
}
|
||||
|
||||
export class UserActions {
|
||||
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
||||
|
||||
logIn(credentials: ICredentials): IAction<IUser, UserActionKeys.USER_LOG_IN> {
|
||||
return {
|
||||
payload: this.http.post('/auth/login', credentials),
|
||||
type: UserActionKeys.USER_LOG_IN,
|
||||
}
|
||||
}
|
||||
|
||||
logOut(): IAction<unknown, UserActionKeys.USER_LOG_OUT> {
|
||||
return {
|
||||
payload: this.http.get('/auth/logout'),
|
||||
type: UserActionKeys.USER_LOG_OUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This makes it very easy to write reducer code.
|
||||
export type UserActionType = ActionTypes<UserActions>
|
||||
3
packages/client/src/actions/index.ts
Normal file
3
packages/client/src/actions/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './IAction'
|
||||
export * from './UnionType'
|
||||
export * from './UserActions'
|
||||
128
packages/client/src/http/HTTPClient.ts
Normal file
128
packages/client/src/http/HTTPClient.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import assert from 'assert'
|
||||
import axios, {AxiosInstance} from 'axios'
|
||||
import {IHTTPClient} from './IHTTPClient'
|
||||
import {IHeader} from './IHeader'
|
||||
import {IMethod, IRoutes} from '@rondo/common'
|
||||
import {ITypedRequestParams} from './ITypedRequestParams'
|
||||
|
||||
export class HTTPClient<T extends IRoutes> implements IHTTPClient<T> {
|
||||
protected readonly axios: AxiosInstance
|
||||
|
||||
constructor(baseURL = '', headers?: IHeader) {
|
||||
this.axios = axios.create({
|
||||
baseURL,
|
||||
headers,
|
||||
})
|
||||
}
|
||||
|
||||
async request<
|
||||
P extends keyof T & string,
|
||||
M extends IMethod,
|
||||
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']> {
|
||||
|
||||
const url = params.path.replace(/:[a-zA-Z0-9-]+/g, (match) => {
|
||||
const key = match.substring(1)
|
||||
assert(params.params, 'Params is required, but not defined')
|
||||
assert(params.params!.hasOwnProperty(key))
|
||||
return params.params![key]
|
||||
})
|
||||
|
||||
return this.axios.request({
|
||||
method: params.method,
|
||||
url,
|
||||
params: params.query,
|
||||
data: params.body,
|
||||
})
|
||||
}
|
||||
|
||||
get<P extends keyof T & string>(
|
||||
path: P,
|
||||
query?: T[P]['get']['query'],
|
||||
params?: T[P]['get']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'get',
|
||||
path,
|
||||
query,
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
post<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['post']['body'],
|
||||
params?: T[P]['post']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'post',
|
||||
path,
|
||||
body,
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
put<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['put']['body'],
|
||||
params?: T[P]['put']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'put',
|
||||
path,
|
||||
body,
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
delete<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['delete']['body'],
|
||||
params?: T[P]['delete']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'delete',
|
||||
path,
|
||||
body,
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
head<P extends keyof T & string>(
|
||||
path: P,
|
||||
query?: T[P]['head']['query'],
|
||||
params?: T[P]['head']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'head',
|
||||
path,
|
||||
params,
|
||||
query,
|
||||
})
|
||||
}
|
||||
|
||||
options<P extends keyof T & string>(
|
||||
path: P,
|
||||
query?: T[P]['options']['query'],
|
||||
params?: T[P]['options']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'options',
|
||||
path,
|
||||
params,
|
||||
query,
|
||||
})
|
||||
}
|
||||
|
||||
patch<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['patch']['body'],
|
||||
params?: T[P]['patch']['params'],
|
||||
) {
|
||||
return this.request({
|
||||
method: 'patch',
|
||||
path,
|
||||
body,
|
||||
params,
|
||||
})
|
||||
}
|
||||
}
|
||||
51
packages/client/src/http/IHTTPClient.ts
Normal file
51
packages/client/src/http/IHTTPClient.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import {IMethod, IRoutes} from '@rondo/common'
|
||||
import {ITypedRequestParams} from './ITypedRequestParams'
|
||||
|
||||
export interface IHTTPClient<T extends IRoutes> {
|
||||
request<
|
||||
P extends keyof T & string,
|
||||
M extends IMethod,
|
||||
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']>
|
||||
|
||||
get<P extends keyof T & string>(
|
||||
path: P,
|
||||
query?: T[P]['get']['query'],
|
||||
params?: T[P]['get']['params'],
|
||||
): Promise<T[P]['get']['response']>
|
||||
|
||||
post<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['post']['body'],
|
||||
params?: T[P]['post']['params'],
|
||||
): Promise<T[P]['post']['response']>
|
||||
|
||||
put<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['put']['body'],
|
||||
params?: T[P]['put']['params'],
|
||||
): Promise<T[P]['put']['response']>
|
||||
|
||||
delete<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['delete']['body'],
|
||||
params?: T[P]['delete']['params'],
|
||||
): Promise<T[P]['delete']['response']>
|
||||
|
||||
head<P extends keyof T & string>(
|
||||
path: P,
|
||||
query?: T[P]['head']['query'],
|
||||
params?: T[P]['head']['params'],
|
||||
): Promise<T[P]['head']['response']>
|
||||
|
||||
options<P extends keyof T & string>(
|
||||
path: P,
|
||||
query?: T[P]['options']['query'],
|
||||
params?: T[P]['options']['params'],
|
||||
): Promise<T[P]['options']['response']>
|
||||
|
||||
patch<P extends keyof T & string>(
|
||||
path: P,
|
||||
body: T[P]['patch']['body'],
|
||||
params?: T[P]['patch']['params'],
|
||||
): Promise<T[P]['patch']['response']>
|
||||
}
|
||||
3
packages/client/src/http/IHeader.ts
Normal file
3
packages/client/src/http/IHeader.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface IHeader {
|
||||
[key: string]: string
|
||||
}
|
||||
13
packages/client/src/http/ITypedRequestParams.ts
Normal file
13
packages/client/src/http/ITypedRequestParams.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import {IRoutes, IMethod} from '@rondo/common'
|
||||
|
||||
export interface ITypedRequestParams<
|
||||
T extends IRoutes,
|
||||
P extends keyof T & string,
|
||||
M extends IMethod,
|
||||
> {
|
||||
method: M,
|
||||
path: P,
|
||||
params?: T[P][M]['params'],
|
||||
query?: T[P][M]['query'],
|
||||
body?: T[P][M]['body'],
|
||||
}
|
||||
2
packages/client/src/http/index.ts
Normal file
2
packages/client/src/http/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './HTTPClient'
|
||||
export * from './IHeader'
|
||||
@ -1,11 +1,5 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
||||
export * from './renderer'
|
||||
|
||||
export {React}
|
||||
export {ReactDOM}
|
||||
|
||||
// import ReactDOM from 'react-dom'
|
||||
// import React from 'react'
|
||||
// import {CComponent} from './components/Component'
|
||||
|
||||
19
packages/client/src/reducers/user.ts
Normal file
19
packages/client/src/reducers/user.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import {IUser} from '@rondo/common'
|
||||
import {UserActionKeys, UserActionType} from '../actions/UserActions'
|
||||
|
||||
interface IState {
|
||||
user?: IUser
|
||||
}
|
||||
|
||||
const defaultState: IState = {
|
||||
user: undefined,
|
||||
}
|
||||
|
||||
export function user(state = defaultState, action: UserActionType): IState {
|
||||
switch (action.type) {
|
||||
case UserActionKeys.USER_LOG_IN:
|
||||
return {user: action.payload}
|
||||
case UserActionKeys.USER_LOG_OUT:
|
||||
return {user: undefined}
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,16 @@
|
||||
import {ICredentials} from './ICredentials'
|
||||
import {IUser} from './IUser'
|
||||
|
||||
export interface IAPIDef {
|
||||
'/auth/register': {
|
||||
'post': {
|
||||
body: {
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
body: ICredentials
|
||||
}
|
||||
}
|
||||
'/auth/login': {
|
||||
'post': {
|
||||
body: {
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
body: ICredentials
|
||||
response: IUser
|
||||
}
|
||||
}
|
||||
'/auth/logout': {
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
export * from './IRoutes'
|
||||
export * from './IAPIDef'
|
||||
export * from './ICredentials'
|
||||
export * from './IRoutes'
|
||||
export * from './IUser'
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import express, {Application} from 'express'
|
||||
import request from 'supertest'
|
||||
import {Authenticator} from './Authenticator'
|
||||
import {ICredentials, IUserService} from '../services'
|
||||
import {ICredentials} from '@rondo/common'
|
||||
import {IUserService} from '../services'
|
||||
import {handlePromise} from './handlePromise'
|
||||
import {urlencoded} from 'body-parser'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {ICredentials} from './ICredentials'
|
||||
import {IUser} from './IUser'
|
||||
import {ICredentials} from '@rondo/common'
|
||||
import {IUser} from '@rondo/common'
|
||||
|
||||
export interface IUserService {
|
||||
createUser(credentials: ICredentials): Promise<IUser>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import createError from 'http-errors'
|
||||
import {BaseService} from './BaseService'
|
||||
import {ICredentials} from './ICredentials'
|
||||
import {ICredentials} from '@rondo/common'
|
||||
import {IUserService} from './IUserService'
|
||||
import {UserEmail} from '../entities/UserEmail'
|
||||
import {User} from '../entities/User'
|
||||
|
||||
@ -1,4 +1,2 @@
|
||||
export * from './UserService'
|
||||
export * from './IUserService'
|
||||
export * from './IUser'
|
||||
export * from './ICredentials'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user