0524 sync
This commit is contained in:
parent
b4ef37624c
commit
02c2645e01
|
@ -14,7 +14,23 @@ module.exports = {
|
|||
rule.use.push({
|
||||
loader: 'sass-resources-loader',
|
||||
options: {
|
||||
resources: [path.join(__dirname, 'styles.scss')]
|
||||
resources: [
|
||||
path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'node_modules',
|
||||
'@angular/material/prebuilt-themes',
|
||||
'indigo-pink.css'
|
||||
),
|
||||
path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'node_modules',
|
||||
'perfect-scrollbar/css',
|
||||
'perfect-scrollbar.css'
|
||||
),
|
||||
path.join(__dirname, 'styles.scss')
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
6
.storybook/preview-head.html
Normal file
6
.storybook/preview-head.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<link
|
||||
href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style></style>
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": [
|
||||
|
|
43
angular.json
43
angular.json
|
@ -1264,6 +1264,49 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ui-material": {
|
||||
"projectType": "library",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "projects/ui-material",
|
||||
"sourceRoot": "projects/ui-material/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/ui-material/tsconfig.lib.json",
|
||||
"project": "projects/ui-material/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "projects/ui-material/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/ui-material/src/test.ts",
|
||||
"tsConfig": "projects/ui-material/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/ui-material/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/ui-material/tsconfig.lib.json",
|
||||
"projects/ui-material/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": ["**/node_modules/**"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"projectType": "library",
|
||||
"schematics": {
|
||||
|
|
52
package-lock.json
generated
52
package-lock.json
generated
|
@ -3503,18 +3503,18 @@
|
|||
"dev": true
|
||||
},
|
||||
"@ucap/ng-store-authentication": {
|
||||
"version": "file:pack/ucap-ng-store-authentication-0.0.10.tgz",
|
||||
"integrity": "sha512-71Jzg9oYSQ89nShT3F64Mfy4edAbmc/vH/0pbPtT0S4zVH/ZMiC11xnocDQTzAKKtP1kXdNGJt/wv1ZbjMNUQQ==",
|
||||
"version": "file:pack/ucap-ng-store-authentication-0.0.11.tgz",
|
||||
"integrity": "sha512-YwLMW+GIR3Rs7LaP+1xOH9KLI5jlpZx8oS7Zl32m6Wbym4ModIcGh21rRrqFhNXky4s9zl+ziaTRpFNCKJRgng==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-store-chat": {
|
||||
"version": "file:pack/ucap-ng-store-chat-0.0.8.tgz",
|
||||
"integrity": "sha512-f/Smoy/A97JV2Tsd7IIAeQcNRrthxKT+S01PrVyzjNktDvcxOurnIXGacytU9sfkEMP2rOFCuWKv5p21rvVg6g==",
|
||||
"version": "file:pack/ucap-ng-store-chat-0.0.13.tgz",
|
||||
"integrity": "sha512-o+BCCSMxneUenRHEW47sSY22+Zt3lyr202Lg4bub9OVRbW5CVohHez8H+JwK+w+Lf8KbqG32V1ZjKLGclTpboA==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-store-group": {
|
||||
"version": "file:pack/ucap-ng-store-group-0.0.9.tgz",
|
||||
"integrity": "sha512-KJ4E/kZECAkT6zwA1FiDCrhGevCx9so2Knz08kU49broquZQlOtbV70tPj1fA0XBnaY3hL7uUKXqvAfC7OXj0g==",
|
||||
"version": "file:pack/ucap-ng-store-group-0.0.14.tgz",
|
||||
"integrity": "sha512-sUmdHO7TD5B33DMAoEnelvqbLXTsWPnK2HC8XQ0FdlfGyUtf3kGpwS4BxduUi5wiZckR3hfuBdpCShIhf/qmeQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-store-organization": {
|
||||
|
@ -3523,33 +3523,39 @@
|
|||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui": {
|
||||
"version": "file:pack/ucap-ng-ui-0.0.11.tgz",
|
||||
"integrity": "sha512-Vrl6LFQyBwju76RALrF0/dH9p+PJ4nX33dy99QSx6RUJHQ80C0qAmO/DFS1Ln0LZaDc4KoYIHTAOLvX4WLHS5w==",
|
||||
"version": "file:pack/ucap-ng-ui-0.0.19.tgz",
|
||||
"integrity": "sha512-UuZSzWM4tBR+e5Z/1PFdNenHS00Pn4K7dTafIicG29YjHE5sTXXRqjDCVrKNxJQoMSEPWjUj7qnTgYwP2U83Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui-authentication": {
|
||||
"version": "file:pack/ucap-ng-ui-authentication-0.0.20.tgz",
|
||||
"integrity": "sha512-1FhqwODVL51NC39mwi/2MECMQiyM+qXAlVp2/BrvN+piXXRz/qp62Iwyf/jww+N8aVCe3dqbktJl/tuPacm4/Q==",
|
||||
"version": "file:pack/ucap-ng-ui-authentication-0.0.24.tgz",
|
||||
"integrity": "sha512-6QMJ8dieTnbPANsBzg2Ll3HH5q6Bzl2iSM19yHq8Ct7XOmElrYqrEZmxbDyYO+aCXIAwd2t7vu+rTsHfz3XOQg==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui-chat": {
|
||||
"version": "file:pack/ucap-ng-ui-chat-0.0.3.tgz",
|
||||
"integrity": "sha512-RRw533PNi0vVCxH1QiogOkJEC/dWGsSFtK3hdJ/ZlcPCT7G81FnnXVY3HPIzu1MhxnSb7KfVJLZhx2RFEfEXWA==",
|
||||
"version": "file:pack/ucap-ng-ui-chat-0.0.9.tgz",
|
||||
"integrity": "sha512-6qvzcTuylkxVjsqajsLW15laOyOskxVMy238/Ju1yYvwCRyHygwS1i67APoG5tv+SWu+l38f9uWIqzfy7WYHkQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui-group": {
|
||||
"version": "file:pack/ucap-ng-ui-group-0.0.30.tgz",
|
||||
"integrity": "sha512-LJXwWZ4anO/ScpI+c6IUfwjmcW9tocQq86/cHi8m6SaQwaMq3jltlN2x8WLzRefd72KysLyJHZrX5L1zMLcXog==",
|
||||
"version": "file:pack/ucap-ng-ui-group-0.0.33.tgz",
|
||||
"integrity": "sha512-c//Jq00drbMGE3Cgwlh19ScXllGERX2eMVWkVjm311Y8HN9oBBT6Aq2uCM23/76P866oNrhecVDfDHgGYzPRjA==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui-material": {
|
||||
"version": "file:pack/ucap-ng-ui-material-0.0.4.tgz",
|
||||
"integrity": "sha512-ySPULAbP+nQ65hBG2VWZ2H5Hr7muuTGGNXs6A+S3lsxLaW452wM3GNyUBhvUopr8LaSsoOPpp4nK1JeC0fG6pA==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui-organization": {
|
||||
"version": "file:pack/ucap-ng-ui-organization-0.0.27.tgz",
|
||||
"integrity": "sha512-BC0Jxoxia/+Kho+1oAXE+7+K9iXLhVYVWPVCmmzSRGYGrIZu1skNzzKCNZh6WxYOr7LAJ6ZOp+FgYDfKS7iHMg==",
|
||||
"version": "file:pack/ucap-ng-ui-organization-0.0.55.tgz",
|
||||
"integrity": "sha512-vfpKd3fbd+I0Od8aB2nIFfjuI7wj3Ziu/uiTEmZxKwZy7uZrNYm59BPbctKW3AQsQ4UtnLofhlBbAA7e9pT80Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-ui-skin-default": {
|
||||
"version": "file:pack/ucap-ng-ui-skin-default-0.0.1.tgz",
|
||||
"integrity": "sha512-kfbbfHZ2b1mQL5SflvM9xn86d53NFEx3yTCaQSx16VSEetbQAtb6Qp1/VedDxK6NcWHp+s/Msw5cfuypN1gwug=="
|
||||
"integrity": "sha512-+lHYAzbnyyWh6hf+Ui7vP/ibyGJXuDUO++82jOiOsnPMCl17hkCCag8vQcB/aVgl0iHmebiPshnsL3CptJfeAg==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/ng-web-socket": {
|
||||
"version": "file:pack/ucap-ng-web-socket-0.0.2.tgz",
|
||||
|
@ -3592,9 +3598,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@ucap/protocol-file": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/protocol-file/-/protocol-file-0.0.4.tgz",
|
||||
"integrity": "sha512-oyne/wiKsEsLzJY9VJUO85AwLtgfq0Dt7RyFLThoqquz6O7lCuWszdtvggAJTgn+XM+nF4hczw2Qm2jwjjCZgQ==",
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/protocol-file/-/protocol-file-0.0.5.tgz",
|
||||
"integrity": "sha512-3XRwtlpcrm2oZeckoOzzAUcqADPCGbgdEb4psfNnphTbGX9nYaBUTpWuLYwD3tVe7Wg4fytaHemcAu8yVZUANw==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/protocol-group": {
|
||||
|
@ -3604,9 +3610,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@ucap/protocol-info": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/protocol-info/-/protocol-info-0.0.5.tgz",
|
||||
"integrity": "sha512-C2+cJrxdUNLVt3E1a54tCpTmEYE16sUGNvdJGUPywbvLAhjWf71ECjGr16bTMcPr/PxmzjZBu9M2Of39sqngOQ==",
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/protocol-info/-/protocol-info-0.0.6.tgz",
|
||||
"integrity": "sha512-qpt0jfmHDyaMGyADzaDMKbbkfD04yEC0u4KDyoMdjnTi0RXA6cilDRGr9TW/bezB9OxS40yNLK6REfh7aSmcUA==",
|
||||
"dev": true
|
||||
},
|
||||
"@ucap/protocol-inner": {
|
||||
|
|
39
package.json
39
package.json
|
@ -6,7 +6,7 @@
|
|||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"build:all": "npm-run-all -s build:logger build:core build:util:all build:api:all build:protocol:all build:native:all build:store:all build:ui:all build:ui-skin:all",
|
||||
"build:all": "npm-run-all -s build:logger build:core build:util:all build:api:all build:protocol:all build:native:all build:store:all build:ui-material:all build:ui:all build:ui-skin:all",
|
||||
"build:api:all": "npm-run-all -s build:api-common build:api-external build:api-message build:api-prompt build:api-public build:pi",
|
||||
"build:api-common": "node ./scripts/build.js api-common",
|
||||
"build:api-external": "node ./scripts/build.js api-external",
|
||||
|
@ -45,15 +45,17 @@
|
|||
"build:store-chat": "node ./scripts/build.js store-chat",
|
||||
"build:store-group": "node ./scripts/build.js store-group",
|
||||
"build:store-organization": "node ./scripts/build.js store-organization",
|
||||
"build:ui-material:all": "npm-run-all -s build:ui-material",
|
||||
"build:ui-material": "node ./scripts/build.js ui-material useScssBundle",
|
||||
"build:ui:all": "npm-run-all -s build:ui build:ui-organization build:ui-authentication build:ui-group build:ui-chat",
|
||||
"build:ui": "node ./scripts/build.js ui",
|
||||
"build:ui-organization": "node ./scripts/build.js ui-organization",
|
||||
"build:ui-authentication": "node ./scripts/build.js ui-authentication",
|
||||
"build:ui-group": "node ./scripts/build.js ui-group",
|
||||
"build:ui-chat": "node ./scripts/build.js ui-chat",
|
||||
"build:ui": "node ./scripts/build.js ui useScssBundle",
|
||||
"build:ui-organization": "node ./scripts/build.js ui-organization useScssBundle",
|
||||
"build:ui-authentication": "node ./scripts/build.js ui-authentication useScssBundle",
|
||||
"build:ui-group": "node ./scripts/build.js ui-group useScssBundle",
|
||||
"build:ui-chat": "node ./scripts/build.js ui-chat useScssBundle",
|
||||
"build:ui-skin:all": "npm-run-all -s build:ui-skin-default",
|
||||
"build:ui-skin-default": "node ./scripts/build.js ui-skin-default useScssBundle",
|
||||
"publish:all": "npm-run-all -s publish:logger publish:core publish:util:all publish:api:all publish:protocol:all publish:native:all publish:store:all publish:ui:all publish:ui-skin:all",
|
||||
"publish:all": "npm-run-all -s publish:logger publish:core publish:util:all publish:api:all publish:protocol:all publish:native:all publish:store:all publish:ui-material:all publish:ui:all publish:ui-skin:all",
|
||||
"publish:api:all": "npm-run-all -s publish:api-common publish:api-external publish:api-message publish:api-prompt publish:api-public publish:pi",
|
||||
"publish:api-common": "cd ./dist/api-common && npm publish",
|
||||
"publish:api-external": "cd ./dist/api-external && npm publish",
|
||||
|
@ -92,6 +94,8 @@
|
|||
"publish:store-chat": "cd ./dist/store-chat && npm publish",
|
||||
"publish:store-group": "cd ./dist/store-group && npm publish",
|
||||
"publish:store-organization": "cd ./dist/store-organization && npm publish",
|
||||
"publish:ui-material:all": "npm-run-all -s publish:ui-material",
|
||||
"publish:ui-material": "cd ./dist/ui-material && npm publish",
|
||||
"publish:ui:all": "npm-run-all -s publish:ui publish:ui-organization publish:ui-authentication publish:ui-group publish:ui-chat",
|
||||
"publish:ui": "cd ./dist/ui && npm publish",
|
||||
"publish:ui-organization": "cd ./dist/ui-organization && npm publish",
|
||||
|
@ -180,15 +184,16 @@
|
|||
"@ucap/ng-protocol-status": "file:pack/ucap-ng-protocol-status-0.0.3.tgz",
|
||||
"@ucap/ng-protocol-sync": "file:pack/ucap-ng-protocol-sync-0.0.3.tgz",
|
||||
"@ucap/ng-protocol-umg": "file:pack/ucap-ng-protocol-umg-0.0.3.tgz",
|
||||
"@ucap/ng-store-authentication": "file:pack/ucap-ng-store-authentication-0.0.10.tgz",
|
||||
"@ucap/ng-store-chat": "file:pack/ucap-ng-store-chat-0.0.8.tgz",
|
||||
"@ucap/ng-store-group": "file:pack/ucap-ng-store-group-0.0.9.tgz",
|
||||
"@ucap/ng-store-authentication": "file:pack/ucap-ng-store-authentication-0.0.11.tgz",
|
||||
"@ucap/ng-store-chat": "file:pack/ucap-ng-store-chat-0.0.13.tgz",
|
||||
"@ucap/ng-store-group": "file:pack/ucap-ng-store-group-0.0.14.tgz",
|
||||
"@ucap/ng-store-organization": "file:pack/ucap-ng-store-organization-0.0.8.tgz",
|
||||
"@ucap/ng-ui": "file:pack/ucap-ng-ui-0.0.11.tgz",
|
||||
"@ucap/ng-ui-authentication": "file:pack/ucap-ng-ui-authentication-0.0.20.tgz",
|
||||
"@ucap/ng-ui-chat": "file:pack/ucap-ng-ui-chat-0.0.3.tgz",
|
||||
"@ucap/ng-ui-group": "file:pack/ucap-ng-ui-group-0.0.30.tgz",
|
||||
"@ucap/ng-ui-organization": "file:pack/ucap-ng-ui-organization-0.0.27.tgz",
|
||||
"@ucap/ng-ui": "file:pack/ucap-ng-ui-0.0.19.tgz",
|
||||
"@ucap/ng-ui-authentication": "file:pack/ucap-ng-ui-authentication-0.0.24.tgz",
|
||||
"@ucap/ng-ui-chat": "file:pack/ucap-ng-ui-chat-0.0.9.tgz",
|
||||
"@ucap/ng-ui-group": "file:pack/ucap-ng-ui-group-0.0.33.tgz",
|
||||
"@ucap/ng-ui-material": "file:pack/ucap-ng-ui-material-0.0.4.tgz",
|
||||
"@ucap/ng-ui-organization": "file:pack/ucap-ng-ui-organization-0.0.55.tgz",
|
||||
"@ucap/ng-ui-skin-default": "file:pack/ucap-ng-ui-skin-default-0.0.1.tgz",
|
||||
"@ucap/ng-web-socket": "file:pack/ucap-ng-web-socket-0.0.2.tgz",
|
||||
"@ucap/ng-web-storage": "file:pack/ucap-ng-web-storage-0.0.3.tgz",
|
||||
|
@ -197,9 +202,9 @@
|
|||
"@ucap/protocol-authentication": "~0.0.5",
|
||||
"@ucap/protocol-buddy": "~0.0.5",
|
||||
"@ucap/protocol-event": "~0.0.5",
|
||||
"@ucap/protocol-file": "~0.0.4",
|
||||
"@ucap/protocol-file": "~0.0.5",
|
||||
"@ucap/protocol-group": "~0.0.5",
|
||||
"@ucap/protocol-info": "~0.0.5",
|
||||
"@ucap/protocol-info": "~0.0.6",
|
||||
"@ucap/protocol-inner": "~0.0.4",
|
||||
"@ucap/protocol-option": "~0.0.7",
|
||||
"@ucap/protocol-ping": "~0.0.4",
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
"@ucap/api-external": "@ucap/api-external",
|
||||
"@ucap/pi": "@ucap/pi",
|
||||
"@ucap/protocol-authentication": "@ucap/protocol-authentication",
|
||||
"@ucap/protocol-info": "@ucap/protocol-info",
|
||||
"@ucap/protocol-option": "@ucap/protocol-option",
|
||||
"@ucap/protocol-query": "@ucap/protocol-query",
|
||||
"@ucap/ng-pi": "@ucap/ng-pi",
|
||||
"@ucap/ng-protocol-authentication": "@ucap/ng-protocol-authentication",
|
||||
"@ucap/ng-protocol-info": "@ucap/ng-protocol-info",
|
||||
"@ucap/ng-protocol-option": "@ucap/ng-protocol-option",
|
||||
"@ucap/ng-protocol-query": "@ucap/ng-protocol-query"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@ucap/ng-store-authentication",
|
||||
"version": "0.0.10",
|
||||
"version": "0.0.11",
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-ucap/"
|
||||
},
|
||||
|
@ -17,10 +17,12 @@
|
|||
"@ucap/protocol-authentication": "~0.0.1",
|
||||
"@ucap/protocol-option": "~0.0.1",
|
||||
"@ucap/protocol-query": "~0.0.1",
|
||||
"@ucap/protocol-info": "~0.0.1",
|
||||
"@ucap/ng-pi": "~0.0.1",
|
||||
"@ucap/ng-protocol-authentication": "~0.0.1",
|
||||
"@ucap/ng-protocol-option": "~0.0.1",
|
||||
"@ucap/ng-protocol-query": "~0.0.1",
|
||||
"@ucap/ng-protocol-info": "~0.0.1",
|
||||
"rxjs": "~6.5.4",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
LoginResponse,
|
||||
LogoutResponse
|
||||
} from '@ucap/protocol-authentication';
|
||||
import { UserResponse, UserRequest } from '@ucap/protocol-info';
|
||||
|
||||
/**
|
||||
* request of web login
|
||||
|
@ -106,3 +107,29 @@ export const sessionDestroyed = createAction(
|
|||
'[ucap::authentication::login] session Destroyed',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
/**
|
||||
* info user request
|
||||
*/
|
||||
export const infoUser = createAction(
|
||||
'[ucap::authentication::login] Info User',
|
||||
props<{ req: UserRequest }>()
|
||||
);
|
||||
|
||||
/**
|
||||
* Success of info user request
|
||||
*/
|
||||
export const infoUserSuccess = createAction(
|
||||
'[ucap::authentication::login] Info User Success',
|
||||
props<{
|
||||
res: UserResponse;
|
||||
}>()
|
||||
);
|
||||
|
||||
/**
|
||||
* Failure of info user request
|
||||
*/
|
||||
export const infoUserFailure = createAction(
|
||||
'[ucap::authentication::login] Info User Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { of } from 'rxjs';
|
||||
import { catchError, map, switchMap } from 'rxjs/operators';
|
||||
import { catchError, map, switchMap, exhaustMap } from 'rxjs/operators';
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
|
@ -7,26 +7,52 @@ import { Actions, ofType, createEffect } from '@ngrx/effects';
|
|||
|
||||
import { PiService } from '@ucap/ng-pi';
|
||||
import { AuthenticationProtocolService } from '@ucap/ng-protocol-authentication';
|
||||
import { InfoProtocolService } from '@ucap/ng-protocol-info';
|
||||
|
||||
import { logout, logoutSuccess } from './actions';
|
||||
import {
|
||||
logout,
|
||||
logoutSuccess,
|
||||
infoUser,
|
||||
infoUserSuccess,
|
||||
infoUserFailure
|
||||
} from './actions';
|
||||
import { UserResponse } from '@ucap/protocol-info';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
logout$ = createEffect(() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(logout),
|
||||
switchMap(action => {
|
||||
switchMap((action) => {
|
||||
return this.authenticationProtocolService.logout({}).pipe(
|
||||
map(res => logoutSuccess({ res })),
|
||||
catchError(error => of(error))
|
||||
map((res) => logoutSuccess({ res })),
|
||||
catchError((error) => of(error))
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
infoUser$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(infoUser),
|
||||
map((action) => action.req),
|
||||
exhaustMap((req) =>
|
||||
this.infoProtocolService.user(req).pipe(
|
||||
map((res: UserResponse) => {
|
||||
return infoUserSuccess({
|
||||
res
|
||||
});
|
||||
}),
|
||||
catchError((error) => of(infoUserFailure({ error })))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private piService: PiService,
|
||||
private authenticationProtocolService: AuthenticationProtocolService
|
||||
private authenticationProtocolService: AuthenticationProtocolService,
|
||||
private infoProtocolService: InfoProtocolService
|
||||
) {}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
|
||||
import { initialState } from './state';
|
||||
import { loginSuccess, logoutSuccess } from './actions';
|
||||
import { loginSuccess, logoutSuccess, infoUserSuccess } from './actions';
|
||||
import { UserInfoUpdateType } from '@ucap/protocol-info';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
|
@ -16,5 +17,41 @@ export const reducer = createReducer(
|
|||
return {
|
||||
...initialState
|
||||
};
|
||||
}),
|
||||
|
||||
on(infoUserSuccess, (state, action) => {
|
||||
let loginRes = {
|
||||
...state.loginRes
|
||||
};
|
||||
|
||||
switch (action.res.type) {
|
||||
case UserInfoUpdateType.Image:
|
||||
loginRes = {
|
||||
...loginRes
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.Intro:
|
||||
loginRes = {
|
||||
...loginRes,
|
||||
userInfo: {
|
||||
...loginRes.userInfo,
|
||||
intro: action.res.info
|
||||
}
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.TelephoneVisible:
|
||||
loginRes = {
|
||||
...loginRes
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
loginRes: {
|
||||
...loginRes
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@ucap/ng-store-chat",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.13",
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-ucap/"
|
||||
},
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { ModuleConfig as CoreModuleConfig } from '@ucap/core';
|
||||
|
||||
// tslint:disable-next-line: no-empty-interface
|
||||
export interface ModuleConfig extends CoreModuleConfig {}
|
||||
export interface ModuleConfig extends CoreModuleConfig {
|
||||
eventRequestInitCount?: number;
|
||||
eventRequestDefaultCount?: number;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ import {
|
|||
ReadNotification,
|
||||
CancelNotification,
|
||||
DelNotification,
|
||||
EventJson
|
||||
EventJson,
|
||||
ReadResponse
|
||||
} from '@ucap/protocol-event';
|
||||
|
||||
import {
|
||||
|
@ -40,7 +41,7 @@ export const eventsSuccess = createAction(
|
|||
props<{
|
||||
eventInfoList: Info<EventJson>[];
|
||||
res: EventInfoResponse;
|
||||
remainInfo: boolean;
|
||||
remainEvent: boolean;
|
||||
}>()
|
||||
);
|
||||
/**
|
||||
|
@ -48,7 +49,7 @@ export const eventsSuccess = createAction(
|
|||
*/
|
||||
export const eventsFailure = createAction(
|
||||
'[ucap::chat::chatting] events Failure',
|
||||
props<{ error: any }>()
|
||||
props<{ roomId: string; error: any }>()
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -74,7 +75,7 @@ export const fileInfosSuccess = createAction(
|
|||
*/
|
||||
export const fileInfosFailure = createAction(
|
||||
'[ucap::chat::chatting] fileInfos Failure',
|
||||
props<{ error: any }>()
|
||||
props<{ roomId: string; error: any }>()
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -84,3 +85,23 @@ export const addEvent = createAction(
|
|||
'[ucap::chat::chatting] addEvent',
|
||||
props<{ req: FileInfoRequest }>()
|
||||
);
|
||||
|
||||
export const read = createAction(
|
||||
'[ucap::chat::chatting] read',
|
||||
props<ReadRequest>()
|
||||
);
|
||||
|
||||
export const readSuccess = createAction(
|
||||
'[ucap::chat::chatting] read Success',
|
||||
props<ReadResponse>()
|
||||
);
|
||||
|
||||
// export const readNotification = createAction(
|
||||
// '[ucap::chat::chatting] Read Notification',
|
||||
// props<ReadNotification>()
|
||||
// );
|
||||
|
||||
export const readFailure = createAction(
|
||||
'[ucap::chat::chatting] read Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
|
|
@ -5,33 +5,165 @@ import {
|
|||
map,
|
||||
catchError,
|
||||
exhaustMap,
|
||||
withLatestFrom
|
||||
debounceTime
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
|
||||
import {
|
||||
RoomInfo,
|
||||
UpdateResponse,
|
||||
OpenResponse,
|
||||
ExitResponse,
|
||||
Open3Response,
|
||||
RoomType,
|
||||
InviteResponse,
|
||||
UpdateTimerSetResponse,
|
||||
ExitForcingResponse
|
||||
} from '@ucap/protocol-room';
|
||||
|
||||
import { EventProtocolService } from '@ucap/ng-protocol-event';
|
||||
import { RoomProtocolService } from '@ucap/ng-protocol-room';
|
||||
import { FileProtocolService } from '@ucap/ng-protocol-file';
|
||||
|
||||
import * as roomActions from '../room/actions';
|
||||
import {
|
||||
events,
|
||||
eventsFailure,
|
||||
eventsSuccess,
|
||||
read,
|
||||
readFailure,
|
||||
readSuccess,
|
||||
fileInfos,
|
||||
fileInfosFailure,
|
||||
fileInfosSuccess
|
||||
} from './actions';
|
||||
|
||||
import { InfoRequest, ReadResponse, FileType } from '@ucap/protocol-event';
|
||||
|
||||
import { ModuleConfig } from '../../config/module-config';
|
||||
import { _MODULE_CONFIG } from '../../config/token';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
selectedRoom$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(roomActions.selectedRoom),
|
||||
debounceTime(300),
|
||||
tap((action) => {
|
||||
const requestCount = this.moduleConfig?.eventRequestInitCount || 50;
|
||||
const req: InfoRequest = {
|
||||
roomId: action.roomId,
|
||||
baseSeq: 0,
|
||||
requestCount
|
||||
};
|
||||
|
||||
this.store.dispatch(events({ req }));
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
events$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(events),
|
||||
map((action) => action.req),
|
||||
switchMap((req) => {
|
||||
return this.eventProtocolService.info(req).pipe(
|
||||
map((res) => {
|
||||
if (!!res && !!res.res) {
|
||||
const infoList = res.infoList;
|
||||
|
||||
this.store.dispatch(
|
||||
eventsSuccess({
|
||||
eventInfoList: infoList,
|
||||
res: res.res,
|
||||
remainEvent:
|
||||
infoList.length === req.requestCount ? true : false
|
||||
})
|
||||
);
|
||||
|
||||
if (req.baseSeq === 0) {
|
||||
// 최초 이벤트 목록 조회.
|
||||
|
||||
// SSVC_TYPE_EVENT_READ_REQ 수행.
|
||||
const maxSeq = Math.max.apply(
|
||||
Math,
|
||||
infoList.map((v) => v.seq)
|
||||
);
|
||||
this.store.dispatch(
|
||||
read({
|
||||
roomId: req.roomId,
|
||||
lastReadSeq: Number(maxSeq)
|
||||
})
|
||||
);
|
||||
|
||||
// File 정보 수집.
|
||||
this.store.dispatch(
|
||||
fileInfos({
|
||||
req: {
|
||||
roomId: res.res.roomId,
|
||||
// { 파일타입 } cf) I : 이미지 V: 동영상 F: 파일 "" 빈값이면 모든 타입을 내려줌
|
||||
type: FileType.All
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}),
|
||||
catchError((error) =>
|
||||
of(eventsFailure({ roomId: req.roomId, error }))
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
read$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(read),
|
||||
exhaustMap((req) =>
|
||||
this.eventProtocolService.read(req).pipe(
|
||||
map((res: ReadResponse) => {
|
||||
this.store.dispatch(readSuccess(res));
|
||||
}),
|
||||
catchError((error) => of(readFailure({ error })))
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
fileInfos$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(fileInfos),
|
||||
switchMap((action) => {
|
||||
return this.fileProtocolService.info(action.req).pipe(
|
||||
map((res) => {
|
||||
this.store.dispatch(
|
||||
fileInfosSuccess({
|
||||
fileInfoList: res.fileInfos,
|
||||
fileInfoCheckList: res.fileInfoChecks,
|
||||
res: res.res
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((error) =>
|
||||
of(fileInfosFailure({ roomId: action.req.roomId, error }))
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private store: Store<any>,
|
||||
private roomProtocolService: RoomProtocolService
|
||||
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
|
||||
private roomProtocolService: RoomProtocolService,
|
||||
private eventProtocolService: EventProtocolService,
|
||||
private fileProtocolService: FileProtocolService
|
||||
) {}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,167 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
|
||||
import { initialState, adapterChatting } from './state';
|
||||
import {
|
||||
initialState,
|
||||
adapterChatting,
|
||||
adapterEventList,
|
||||
Chatting,
|
||||
adapterFileInfoList,
|
||||
adapterFileInfoCheckList
|
||||
} from './state';
|
||||
|
||||
export const reducer = createReducer(initialState);
|
||||
import * as roomActions from '../room/actions';
|
||||
import {
|
||||
eventsSuccess,
|
||||
eventsFailure,
|
||||
readSuccess,
|
||||
fileInfosSuccess,
|
||||
fileInfosFailure
|
||||
} from './actions';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
|
||||
on(roomActions.selectedRoom, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
activeRoomId: action.roomId
|
||||
};
|
||||
}),
|
||||
|
||||
on(roomActions.clearSelectedRoom, (state, action) => {
|
||||
if (action.roomId === state.activeRoomId) {
|
||||
return {
|
||||
...state,
|
||||
activeRoomId: null
|
||||
};
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
}),
|
||||
|
||||
on(eventsSuccess, (state, action) => {
|
||||
const roomId = action.res.roomId;
|
||||
|
||||
const chatting = state.chattings.entities[roomId] || {};
|
||||
let trgtChatting: Chatting = {
|
||||
roomId,
|
||||
|
||||
eventListProcessing: false,
|
||||
eventList: adapterEventList.getInitialState(),
|
||||
eventStatus: null,
|
||||
remainEvent: false,
|
||||
|
||||
fileInfoListProcessing: false,
|
||||
fileInfoList: adapterFileInfoList.getInitialState(),
|
||||
fileInfoCheckList: adapterFileInfoCheckList.getInitialState(),
|
||||
fileInfoSyncDate: '',
|
||||
...chatting
|
||||
};
|
||||
|
||||
trgtChatting = {
|
||||
...trgtChatting,
|
||||
eventList: adapterEventList.upsertMany(action.eventInfoList, {
|
||||
...trgtChatting.eventList
|
||||
}),
|
||||
eventStatus: action.res,
|
||||
remainEvent: action.remainEvent,
|
||||
eventListProcessing: false
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
chattings: adapterChatting.upsertOne(trgtChatting, {
|
||||
...state.chattings
|
||||
})
|
||||
};
|
||||
}),
|
||||
|
||||
on(eventsFailure, (state, action) => {
|
||||
const roomId = action.roomId;
|
||||
|
||||
const chatting = state.chattings.entities[roomId];
|
||||
let trgtChatting: Chatting;
|
||||
if (!!chatting) {
|
||||
trgtChatting = {
|
||||
...chatting,
|
||||
eventListProcessing: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
chattings: adapterChatting.upsertOne(trgtChatting, {
|
||||
...state.chattings
|
||||
})
|
||||
};
|
||||
}),
|
||||
|
||||
on(fileInfosSuccess, (state, action) => {
|
||||
const roomId = action.res?.roomId;
|
||||
|
||||
if (!roomId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const chatting = state.chattings.entities[roomId] || {};
|
||||
let trgtChatting: Chatting = {
|
||||
roomId,
|
||||
|
||||
eventListProcessing: false,
|
||||
eventList: adapterEventList.getInitialState(),
|
||||
eventStatus: null,
|
||||
remainEvent: false,
|
||||
|
||||
fileInfoListProcessing: false,
|
||||
fileInfoList: adapterFileInfoList.getInitialState(),
|
||||
fileInfoCheckList: adapterFileInfoCheckList.getInitialState(),
|
||||
fileInfoSyncDate: '',
|
||||
...chatting
|
||||
};
|
||||
|
||||
const fileInfoList = action.fileInfoList;
|
||||
const fileInfoCheckList = action.fileInfoCheckList;
|
||||
|
||||
trgtChatting = {
|
||||
...trgtChatting,
|
||||
fileInfoList: !!fileInfoList
|
||||
? adapterFileInfoList.upsertMany(fileInfoList, {
|
||||
...trgtChatting.fileInfoList
|
||||
})
|
||||
: trgtChatting.fileInfoList,
|
||||
fileInfoCheckList: !!fileInfoCheckList
|
||||
? adapterFileInfoCheckList.upsertMany(fileInfoCheckList, {
|
||||
...trgtChatting.fileInfoCheckList
|
||||
})
|
||||
: trgtChatting.fileInfoCheckList,
|
||||
fileInfoListProcessing: false
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
chattings: adapterChatting.upsertOne(trgtChatting, {
|
||||
...state.chattings
|
||||
})
|
||||
};
|
||||
}),
|
||||
|
||||
on(fileInfosFailure, (state, action) => {
|
||||
const roomId = action.roomId;
|
||||
|
||||
const chatting = state.chattings.entities[roomId];
|
||||
let trgtChatting: Chatting;
|
||||
if (!!chatting) {
|
||||
trgtChatting = {
|
||||
...chatting,
|
||||
fileInfoListProcessing: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
chattings: adapterChatting.upsertOne(trgtChatting, {
|
||||
...state.chattings
|
||||
})
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
@ -10,19 +10,19 @@ export interface FileInfoListState extends EntityState<FileInfo> {}
|
|||
export interface FileInfoCheckListState extends EntityState<FileDownloadInfo> {}
|
||||
|
||||
export const adapterEventList = createEntityAdapter<Info<EventJson>>({
|
||||
selectId: info => info.seq,
|
||||
selectId: (info) => info.seq,
|
||||
sortComparer: (a, b) => {
|
||||
return a.seq - b.seq;
|
||||
}
|
||||
});
|
||||
export const adapterFileInfoList = createEntityAdapter<FileInfo>({
|
||||
selectId: info => info.seq,
|
||||
selectId: (info) => info.seq,
|
||||
sortComparer: (a, b) => {
|
||||
return b.seq - a.seq;
|
||||
}
|
||||
});
|
||||
export const adapterFileInfoCheckList = createEntityAdapter<FileDownloadInfo>({
|
||||
selectId: info => info.seq,
|
||||
selectId: (info) => info.seq,
|
||||
sortComparer: (a, b) => {
|
||||
return b.seq - a.seq;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ export interface Chatting {
|
|||
eventListProcessing?: boolean;
|
||||
eventList?: EventListState;
|
||||
eventStatus?: InfoResponse | null;
|
||||
remainEvent?: false;
|
||||
remainEvent?: boolean;
|
||||
|
||||
fileInfoListProcessing?: boolean;
|
||||
fileInfoList?: FileInfoListState;
|
||||
|
@ -76,9 +76,11 @@ export interface Chatting {
|
|||
export interface ChattingState extends EntityState<Chatting> {}
|
||||
|
||||
export const adapterChatting = createEntityAdapter<Chatting>({
|
||||
selectId: chatting => chatting.roomId
|
||||
selectId: (chatting) => chatting.roomId
|
||||
});
|
||||
|
||||
const chattingInitialState: ChattingState = adapterChatting.getInitialState({});
|
||||
|
||||
const {
|
||||
selectAll: selectAllForChatting,
|
||||
selectEntities: selectEntitiesForChatting,
|
||||
|
@ -86,26 +88,14 @@ const {
|
|||
selectTotal: selectTotalForChatting
|
||||
} = adapterChatting.getSelectors();
|
||||
|
||||
const chattingInitialState: ChattingState = adapterChatting.getInitialState({
|
||||
roomId: undefined,
|
||||
|
||||
eventListProcessing: false,
|
||||
eventList: eventListInitialState,
|
||||
eventStatus: undefined,
|
||||
remainEvent: false,
|
||||
|
||||
fileInfoListProcessing: false,
|
||||
fileInfoList: fileInfoListInitialState,
|
||||
fileInfoCheckList: fileInfoCheckListInitialState,
|
||||
fileInfoSyncDate: undefined
|
||||
});
|
||||
|
||||
export interface State {
|
||||
chattings: ChattingState;
|
||||
activeRoomId: string | null;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
chattings: chattingInitialState
|
||||
chattings: chattingInitialState,
|
||||
activeRoomId: null
|
||||
};
|
||||
|
||||
export function selectors<S>(selector: Selector<any, State>) {
|
||||
|
@ -115,46 +105,55 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
);
|
||||
|
||||
const selectChatting = createSelector(
|
||||
selector,
|
||||
selectEntitiesForChatting,
|
||||
(state: State, entities: Dictionary<Chatting>, roomId: string) =>
|
||||
entities && entities[roomId]
|
||||
selectChattings,
|
||||
(state: ChattingState, roomId: string) => {
|
||||
return state.entities && state.entities[roomId];
|
||||
}
|
||||
);
|
||||
|
||||
const selectChattingEventListProcessing = createSelector(
|
||||
selectChatting,
|
||||
state => state.eventListProcessing
|
||||
(state) => state.eventListProcessing
|
||||
);
|
||||
const selectChattingEventList = createSelector(
|
||||
selectChatting,
|
||||
state => state.eventList
|
||||
selectChattings,
|
||||
(state: ChattingState, roomId: string) => {
|
||||
const chatting = state.entities && state.entities[roomId];
|
||||
if (!!chatting) {
|
||||
return chatting?.eventList;
|
||||
} else {
|
||||
return adapterEventList.getInitialState();
|
||||
}
|
||||
}
|
||||
);
|
||||
const selectChattingEventStatus = createSelector(
|
||||
selectChatting,
|
||||
state => state.eventStatus
|
||||
(state) => state.eventStatus
|
||||
);
|
||||
const selectChattingRemainEvent = createSelector(
|
||||
selectChatting,
|
||||
state => state.remainEvent
|
||||
(state) => state.remainEvent
|
||||
);
|
||||
const selectChattingFileInfoListProcessing = createSelector(
|
||||
selectChatting,
|
||||
state => state.fileInfoListProcessing
|
||||
(state) => state.fileInfoListProcessing
|
||||
);
|
||||
const selectChattingFileInfoList = createSelector(
|
||||
selectChatting,
|
||||
state => state.fileInfoList
|
||||
(state) => state.fileInfoList
|
||||
);
|
||||
const selectChattingFileInfoCheckList = createSelector(
|
||||
selectChatting,
|
||||
state => state.fileInfoCheckList
|
||||
(state) => state.fileInfoCheckList
|
||||
);
|
||||
const selectChattingFileInfoSyncDate = createSelector(
|
||||
selectChatting,
|
||||
state => state.fileInfoSyncDate
|
||||
(state) => state.fileInfoSyncDate
|
||||
);
|
||||
|
||||
return {
|
||||
activeRoomId: createSelector(selector, (state) => state.activeRoomId),
|
||||
|
||||
chattings: createSelector(selectChattings, selectAllForChatting),
|
||||
chatting: selectChatting,
|
||||
|
||||
|
|
|
@ -26,6 +26,21 @@ import {
|
|||
UserInfoShort
|
||||
} from '@ucap/protocol-room';
|
||||
|
||||
/**
|
||||
* retrieve selected Room.
|
||||
*/
|
||||
export const selectedRoom = createAction(
|
||||
'[ucap::chat::selectedRoom] selected room',
|
||||
props<{ roomId: string; localeCode: LocaleCode }>()
|
||||
);
|
||||
/**
|
||||
* clear selected Room.
|
||||
*/
|
||||
export const clearSelectedRoom = createAction(
|
||||
'[ucap::chat::clearSelectedRoom] clear Selected Room',
|
||||
props<{ roomId: string }>()
|
||||
);
|
||||
|
||||
/**
|
||||
* retrieve list of room information and list of user information per room
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,9 @@ import {
|
|||
map,
|
||||
switchMap,
|
||||
exhaustMap,
|
||||
withLatestFrom
|
||||
withLatestFrom,
|
||||
tap,
|
||||
debounceTime
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
@ -21,7 +23,8 @@ import {
|
|||
UpdateResponse,
|
||||
InviteResponse,
|
||||
ExitForcingResponse,
|
||||
UpdateTimerSetResponse
|
||||
UpdateTimerSetResponse,
|
||||
InfoRequest
|
||||
} from '@ucap/protocol-room';
|
||||
|
||||
import { RoomProtocolService } from '@ucap/ng-protocol-room';
|
||||
|
@ -73,7 +76,8 @@ import {
|
|||
rooms2Failure,
|
||||
delMulti,
|
||||
delMultiSuccess,
|
||||
delMultiFailure
|
||||
delMultiFailure,
|
||||
selectedRoom
|
||||
} from './actions';
|
||||
|
||||
@Injectable()
|
||||
|
@ -85,6 +89,29 @@ export class Effects {
|
|||
);
|
||||
});
|
||||
|
||||
selectedRoom$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(selectedRoom),
|
||||
debounceTime(300),
|
||||
tap((action) => {
|
||||
const req: InfoRequest = {
|
||||
...action,
|
||||
isDetail: false
|
||||
};
|
||||
|
||||
console.log(req);
|
||||
|
||||
// retrieve room info
|
||||
this.store.dispatch(room({ req }));
|
||||
|
||||
// retrieve event info >> chatting.effect.selectedRoom$
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
rooms$ = createEffect(() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(rooms),
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
delMultiSuccess,
|
||||
updateSuccess
|
||||
} from './actions';
|
||||
import { userInfo } from 'os';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
|
@ -214,7 +215,9 @@ export const reducer = createReducer(
|
|||
return {
|
||||
...state,
|
||||
rooms: adapterRoom.removeOne(roomId, { ...state.rooms }),
|
||||
roomUsers: adapterRoomUser.removeOne(roomId, { ...state.roomUsers }),
|
||||
roomUsers: adapterRoomUser.removeOne(roomId, {
|
||||
...state.roomUsers
|
||||
}),
|
||||
roomUsersShort: adapterRoomUserShort.removeOne(roomId, {
|
||||
...state.roomUsersShort
|
||||
})
|
||||
|
@ -231,10 +234,72 @@ export const reducer = createReducer(
|
|||
return {
|
||||
...state,
|
||||
rooms: adapterRoom.removeMany(roomIds, { ...state.rooms }),
|
||||
roomUsers: adapterRoomUser.removeMany(roomIds, { ...state.roomUsers }),
|
||||
roomUsers: adapterRoomUser.removeMany(roomIds, {
|
||||
...state.roomUsers
|
||||
}),
|
||||
roomUsersShort: adapterRoomUserShort.removeMany(roomIds, {
|
||||
...state.roomUsersShort
|
||||
})
|
||||
};
|
||||
}),
|
||||
|
||||
/**
|
||||
* [Chatting Action watching.]
|
||||
*/
|
||||
on(chattingActions.readSuccess, (state, action) => {
|
||||
const roomId = action.roomId;
|
||||
const trgtUserSeq = action.SENDER_SEQ;
|
||||
|
||||
if (!roomId || !trgtUserSeq) {
|
||||
return state;
|
||||
}
|
||||
|
||||
let roomUser: RoomUserMap = state.roomUsers.entities[roomId];
|
||||
if (!!roomUser) {
|
||||
roomUser = {
|
||||
...roomUser,
|
||||
userInfos: state.roomUsers.entities[roomId].userInfos.map(
|
||||
(roomUserInfo) => {
|
||||
if (roomUserInfo.seq === Number(trgtUserSeq)) {
|
||||
return {
|
||||
...roomUserInfo,
|
||||
lastReadEventSeq: action.lastReadSeq
|
||||
};
|
||||
} else {
|
||||
return roomUserInfo;
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
let roomUserShort: RoomUserShortMap = state.roomUsersShort.entities[roomId];
|
||||
if (!!roomUserShort) {
|
||||
roomUserShort = {
|
||||
...roomUserShort,
|
||||
userInfos: state.roomUsersShort.entities[roomId].userInfos.map(
|
||||
(roomUserInfo) => {
|
||||
if (roomUserInfo.seq === Number(trgtUserSeq)) {
|
||||
return { ...roomUserInfo, lastReadEventSeq: action.lastReadSeq };
|
||||
} else {
|
||||
return roomUserInfo;
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
roomUsers: !!roomUser
|
||||
? adapterRoomUser.upsertOne(roomUser, {
|
||||
...state.roomUsers
|
||||
})
|
||||
: state.roomUsers,
|
||||
roomUsersShort: !!roomUserShort
|
||||
? adapterRoomUserShort.upsertOne(roomUserShort, {
|
||||
...state.roomUsersShort
|
||||
})
|
||||
: state.roomUsersShort
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
@ -101,9 +101,9 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
rooms: createSelector(selectRooms, selectAllForRoom),
|
||||
room: createSelector(
|
||||
selectRooms,
|
||||
selectEntitiesForRoom,
|
||||
(roomState: RoomState, entities: Dictionary<RoomInfo>, roomId: string) =>
|
||||
entities && entities[roomId]
|
||||
(roomState: RoomState, roomId: string) => {
|
||||
return roomState.entities && roomState.entities[roomId];
|
||||
}
|
||||
),
|
||||
roomsSyncDate: createSelector(
|
||||
selectRooms,
|
||||
|
@ -112,12 +112,9 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
roomUsers: createSelector(selectRoomUsers, selectAllForRoomUser),
|
||||
roomUser: createSelector(
|
||||
selectRoomUsers,
|
||||
selectEntitiesForRoomUser,
|
||||
(
|
||||
roomUserState: RoomUserState,
|
||||
entities: Dictionary<RoomUserDetailData>,
|
||||
roomId: string
|
||||
) => entities && entities[roomId]
|
||||
(roomUserState: RoomUserState, roomId: string) => {
|
||||
return roomUserState.entities && roomUserState.entities[roomId];
|
||||
}
|
||||
),
|
||||
roomUsersShort: createSelector(
|
||||
selectRoomUsersShort,
|
||||
|
@ -125,12 +122,11 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
),
|
||||
roomUserShort: createSelector(
|
||||
selectRoomUsersShort,
|
||||
selectEntitiesForRoomUserShort,
|
||||
(
|
||||
roomUserShortState: RoomUserShortState,
|
||||
entities: Dictionary<RoomUserData>,
|
||||
roomId: string
|
||||
) => entities && entities[roomId]
|
||||
(roomUserShortState: RoomUserShortState, roomId: string) => {
|
||||
return (
|
||||
roomUserShortState.entities && roomUserShortState.entities[roomId]
|
||||
);
|
||||
}
|
||||
),
|
||||
unreadTotal: createSelector(
|
||||
selectRooms,
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
"@ucap/protocol-group": "@ucap/protocol-group",
|
||||
"@ucap/protocol-buddy": "@ucap/protocol-buddy",
|
||||
"@ucap/protocol-query": "@ucap/protocol-query",
|
||||
"@ucap/protocol-info": "@ucap/protocol-info",
|
||||
"@ucap/ng-protocol-buddy": "@ucap/ng-protocol-buddy",
|
||||
"@ucap/ng-protocol-group": "@ucap/ng-protocol-group",
|
||||
"@ucap/ng-protocol-sync": "@ucap/ng-protocol-sync",
|
||||
"@ucap/ng-protocol-info": "@ucap/ng-protocol-info",
|
||||
"@ucap/ng-store-organization": "@ucap/ng-store-organization",
|
||||
"@ucap/ng-store-authentication": "@ucap/ng-store-authentication"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@ucap/ng-store-group",
|
||||
"version": "0.0.9",
|
||||
"version": "0.0.14",
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-ucap/"
|
||||
},
|
||||
|
@ -12,11 +12,13 @@
|
|||
"@ucap/protocol-group": "~0.0.1",
|
||||
"@ucap/protocol-query": "~0.0.1",
|
||||
"@ucap/protocol-sync": "~0.0.1",
|
||||
"@ucap/protocol-info": "~0.0.1",
|
||||
"@ucap/ng-protocol-buddy": "~0.0.1",
|
||||
"@ucap/ng-protocol-group": "~0.0.1",
|
||||
"@ucap/ng-protocol-sync": "~0.0.1",
|
||||
"@ucap/ng-store-organization": "~0.0.1",
|
||||
"@ucap/ng-store-authentication": "~0.0.1",
|
||||
"@ucap/ng-protocol-info": "~0.0.1",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ import {
|
|||
UpdateRequest as BuddyUpdateRequest,
|
||||
UpdateResponse as BuddyUpdateResponse
|
||||
} from '@ucap/protocol-buddy';
|
||||
import {
|
||||
UserNicknameRequest as NicknameRequest,
|
||||
UserNicknameResponse as NicknameResponse
|
||||
} from '@ucap/protocol-info';
|
||||
|
||||
/**
|
||||
* retrieve list of buddy
|
||||
|
@ -116,3 +120,25 @@ export const updateFailure = createAction(
|
|||
'[ucap::group::buddy] update Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
/**
|
||||
* 동료 닉네임 변경
|
||||
*/
|
||||
export const nickname = createAction(
|
||||
'[ucap::group::buddy] user nickname',
|
||||
props<{ req: NicknameRequest }>()
|
||||
);
|
||||
/**
|
||||
* Success of update request
|
||||
*/
|
||||
export const nicknameSuccess = createAction(
|
||||
'[ucap::group::buddy] user nickname Success',
|
||||
props<{ res: NicknameResponse }>()
|
||||
);
|
||||
/**
|
||||
* Failure of update request
|
||||
*/
|
||||
export const nicknameFailure = createAction(
|
||||
'[ucap::group::buddy] user nickname Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
|
|
@ -19,6 +19,11 @@ import {
|
|||
UpdateResponse as BuddyUpdateResponse
|
||||
} from '@ucap/protocol-buddy';
|
||||
|
||||
import {
|
||||
UserNicknameRequest as NicknameRequest,
|
||||
UserNicknameResponse as NicknameResponse
|
||||
} from '@ucap/protocol-info';
|
||||
|
||||
import { SyncProtocolService } from '@ucap/ng-protocol-sync';
|
||||
|
||||
import { BuddyProtocolService } from '@ucap/ng-protocol-buddy';
|
||||
|
@ -43,6 +48,9 @@ import {
|
|||
update,
|
||||
updateSuccess,
|
||||
updateFailure,
|
||||
nickname,
|
||||
nicknameSuccess,
|
||||
nicknameFailure,
|
||||
delAndClear
|
||||
} from './actions';
|
||||
|
||||
|
@ -50,6 +58,7 @@ import { BuddySelector, GroupSelector } from '../state';
|
|||
|
||||
import { ModuleConfig } from '../../config/module-config';
|
||||
import { _MODULE_CONFIG } from '../../config/token';
|
||||
import { InfoProtocolService } from '@ucap/ng-protocol-info';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
|
@ -126,7 +135,7 @@ export class Effects {
|
|||
),
|
||||
tap(([req, groupList, myDeptUserList]) => {
|
||||
for (const group of groupList) {
|
||||
if (group.userSeqs.indexOf(String(req.seq)) > -1) {
|
||||
if (group.userSeqs.indexOf(req.seq as any) > -1) {
|
||||
// 소속부서(내부서) 고정그룹 사용시 소속부서원을 삭제하지 않는다.
|
||||
if (
|
||||
!!this.moduleConfig.useMyDeptGroup &&
|
||||
|
@ -145,7 +154,7 @@ export class Effects {
|
|||
groupSeq: group.seq,
|
||||
groupName: group.name,
|
||||
userSeqs: group.userSeqs.filter(
|
||||
(userSeq) => userSeq !== String(req.seq)
|
||||
(userSeq) => userSeq !== (req.seq as any)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
@ -158,8 +167,9 @@ export class Effects {
|
|||
if (
|
||||
!!this.moduleConfig.useMyDeptGroup &&
|
||||
this.moduleConfig.useMyDeptGroup &&
|
||||
!!myDeptUserList &&
|
||||
myDeptUserList.filter(
|
||||
(deptUser) => deptUser.seq === String(req.seq)
|
||||
(deptUser) => deptUser.seq === (req.seq as any)
|
||||
).length > 0
|
||||
) {
|
||||
// skip;;
|
||||
|
@ -198,6 +208,21 @@ export class Effects {
|
|||
)
|
||||
);
|
||||
|
||||
nickname$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(nickname),
|
||||
map((action) => action.req),
|
||||
exhaustMap((req) =>
|
||||
this.infoProtocolService.userNickname(req).pipe(
|
||||
map((res: NicknameResponse) => {
|
||||
return nicknameSuccess({ res });
|
||||
}),
|
||||
catchError((error) => of(nicknameFailure({ error })))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
groupCreateSuccess$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
|
@ -215,7 +240,7 @@ export class Effects {
|
|||
}
|
||||
|
||||
const index = buddyList.findIndex(
|
||||
(b) => String(b.seq) === userSeq
|
||||
(b) => b.seq === Number(userSeq)
|
||||
);
|
||||
if (-1 < index) {
|
||||
addBuddyList.push(userSeq);
|
||||
|
@ -251,7 +276,7 @@ export class Effects {
|
|||
}
|
||||
|
||||
const index = buddyList.findIndex(
|
||||
(b) => String(b.seq) === userSeq
|
||||
(b) => b.seq === Number(userSeq)
|
||||
);
|
||||
if (-1 < index) {
|
||||
addBuddyList.push(userSeq);
|
||||
|
@ -284,6 +309,7 @@ export class Effects {
|
|||
private store: Store<any>,
|
||||
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
|
||||
private syncProtocolService: SyncProtocolService,
|
||||
private buddyProtocolService: BuddyProtocolService
|
||||
private buddyProtocolService: BuddyProtocolService,
|
||||
private infoProtocolService: InfoProtocolService
|
||||
) {}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,12 @@ import { createReducer, on } from '@ngrx/store';
|
|||
import { UserInfo } from '@ucap/protocol-sync';
|
||||
|
||||
import { initialState, adapterBuddy } from './state';
|
||||
import { buddy2Success, delSuccess, updateSuccess } from './actions';
|
||||
import {
|
||||
buddy2Success,
|
||||
delSuccess,
|
||||
updateSuccess,
|
||||
nicknameSuccess
|
||||
} from './actions';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
|
@ -34,6 +39,19 @@ export const reducer = createReducer(
|
|||
isFavorit: res.isFavorit
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
buddies: adapterBuddy.upsertOne(userInfo, { ...state.buddies })
|
||||
};
|
||||
}),
|
||||
|
||||
on(nicknameSuccess, (state, action) => {
|
||||
const res = action.res;
|
||||
const userInfo: UserInfo = {
|
||||
...state.buddies.entities[res.userSeq],
|
||||
nickName: res.nickname
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
buddies: adapterBuddy.upsertOne(userInfo, { ...state.buddies })
|
||||
|
|
|
@ -128,8 +128,7 @@ export class Effects {
|
|||
)
|
||||
);
|
||||
|
||||
updateMember$ = createEffect(
|
||||
() => {
|
||||
updateMember$ = createEffect(() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(updateMember),
|
||||
withLatestFrom(
|
||||
|
@ -138,17 +137,19 @@ export class Effects {
|
|||
),
|
||||
switchMap(([action, groupList, myDeptUserList]) => {
|
||||
const targetGroup = action.targetGroup;
|
||||
const targetUserSeqs = action.targetUserSeqs;
|
||||
const targetUserSeqs = action.targetUserSeqs as any;
|
||||
|
||||
// Del Buddy
|
||||
let userSeqsForDelete: string[] = targetGroup.userSeqs.filter(
|
||||
(v) => targetUserSeqs.indexOf(v) < 0
|
||||
(v) => targetUserSeqs.indexOf(v + '') < 0
|
||||
);
|
||||
|
||||
// 소속부서(내부서) 고정그룹 사용시 소속부서원을 삭제하지 않는다.
|
||||
if (
|
||||
!!this.moduleConfig.useMyDeptGroup &&
|
||||
this.moduleConfig.useMyDeptGroup
|
||||
this.moduleConfig.useMyDeptGroup &&
|
||||
!!myDeptUserList &&
|
||||
myDeptUserList.length > 0
|
||||
) {
|
||||
userSeqsForDelete = userSeqsForDelete.filter(
|
||||
(delbuddy) =>
|
||||
|
@ -188,9 +189,7 @@ export class Effects {
|
|||
];
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
});
|
||||
|
||||
moveMember$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"dest": "../../dist/ui-authentication",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts",
|
||||
"styleIncludePaths": ["./src/assets/scss"],
|
||||
"umdModuleIds": {
|
||||
"moment": "moment",
|
||||
"@ucap/pi": "@ucap/pi",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@ucap/ng-ui-authentication",
|
||||
"version": "0.0.20",
|
||||
"version": "0.0.24",
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-ucap/"
|
||||
},
|
||||
|
@ -10,9 +10,10 @@
|
|||
"@angular/core": "^9.0.2",
|
||||
"@angular/material": "^9.0.0",
|
||||
"@ucap/core": "~0.0.1",
|
||||
"@ucap/uc-scss": "~0.0.1",
|
||||
"@ucap/ui-scss": "~0.0.1",
|
||||
"@ucap/ng-i18n": "~0.0.1",
|
||||
"@ucap/ng-ui": "~0.0.1",
|
||||
"@ucap/ng-ui-material": "~0.0.1",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
|
|
11
projects/ui-authentication/scss-bundle.config.json
Normal file
11
projects/ui-authentication/scss-bundle.config.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"bundlerOptions": {
|
||||
"entryFile": "./projects/ui-authentication/src/assets/scss/_theme.scss",
|
||||
"rootDir": "./projects/ui-authentication/src/assets/scss/",
|
||||
"outFile": "./dist/ui-authentication/_theme.scss",
|
||||
"dedupeGlobs": [],
|
||||
"includePaths": [],
|
||||
"ignoreImports": ["~@ucap/.*", "~@angular/.*"],
|
||||
"logLevel": "silent"
|
||||
}
|
||||
}
|
2
projects/ui-authentication/src/assets/scss/_theme.scss
Normal file
2
projects/ui-authentication/src/assets/scss/_theme.scss
Normal file
|
@ -0,0 +1,2 @@
|
|||
@import '../../lib/components/change-password.component.theme.scss';
|
||||
@import '../../lib/components/login.component.theme.scss';
|
|
@ -30,8 +30,11 @@
|
|||
}
|
||||
|
||||
.separator {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
font: {
|
||||
size: 15px;
|
||||
weight: 600;
|
||||
}
|
||||
|
||||
margin: 24px auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -2,58 +2,17 @@ import { moduleMetadata } from '@storybook/angular';
|
|||
import { action } from '@storybook/addon-actions';
|
||||
import { linkTo } from '@storybook/addon-links';
|
||||
|
||||
import { ChangePasswordComponent } from './change-password.component';
|
||||
import { AuthenticationUiModule } from '../authentication-ui.module';
|
||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ChangeDetectorRef } from '@angular/core';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { I18nService, UCAP_I18N_NAMESPACE, I18nModule } from '@ucap/ng-i18n';
|
||||
import { LogService } from '@ucap/logger';
|
||||
import { Company } from '@ucap/api-external';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
export default {
|
||||
title: 'ChangePasswordComponent',
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { I18nService, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSelectModule,
|
||||
import { AuthenticationUiModule } from '../authentication-ui.module';
|
||||
|
||||
I18nModule
|
||||
],
|
||||
providers: [
|
||||
AuthenticationUiModule,
|
||||
{ provide: FormBuilder, useValue: new FormBuilder() },
|
||||
{ provide: I18nService, useValue: new I18nService(new LogService({})) },
|
||||
{
|
||||
provide: UCAP_I18N_NAMESPACE,
|
||||
useValue: 'authentication'
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
excludeStories: /.*Data$/
|
||||
};
|
||||
import { ChangePasswordComponent } from './change-password.component';
|
||||
|
||||
export const actionsData = {
|
||||
changePassword: action('changePassword')
|
||||
|
@ -61,6 +20,25 @@ export const actionsData = {
|
|||
|
||||
export const inputData = {};
|
||||
|
||||
export default {
|
||||
title: 'ui-authentication::ChangePasswordComponent',
|
||||
component: ChangePasswordComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [BrowserModule, BrowserAnimationsModule, AuthenticationUiModule],
|
||||
providers: [
|
||||
{ provide: FormBuilder, useClass: FormBuilder },
|
||||
{ provide: LogService, useValue: new LogService({}) },
|
||||
{ provide: I18nService, useClass: I18nService },
|
||||
{
|
||||
provide: UCAP_I18N_NAMESPACE,
|
||||
useValue: 'authentication'
|
||||
}
|
||||
]
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
export const Default = () => ({
|
||||
component: ChangePasswordComponent,
|
||||
props: {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
@import '~@ucap/ng-ui-material/material';
|
||||
|
||||
@mixin ucap-authentication-change-password-theme($theme) {
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$warn: map-get($theme, warn);
|
||||
$background: map-get($theme, background);
|
||||
$foreground: map-get($theme, foreground);
|
||||
|
||||
.ucap-authentication-change-password-container {
|
||||
border-color: mat-color($foreground, secondary-text);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin ucap-authentication-change-password-typography($config) {
|
||||
.ucap-authentication-change-password-container {
|
||||
font-family: mat-font-family($config);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
@import '~@ucap/ui-scss/ucap';
|
||||
@import '~@ucap/ng-ui-material/material';
|
||||
|
||||
.ucap-authentication-login-container {
|
||||
top: 0;
|
||||
|
@ -9,7 +9,9 @@
|
|||
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
border-radius: 0px;
|
||||
font-size: 14px;
|
||||
font: {
|
||||
size: 14px;
|
||||
}
|
||||
|
||||
text-align: center;
|
||||
|
||||
|
@ -52,7 +54,9 @@
|
|||
display: block;
|
||||
border-radius: 0;
|
||||
line-height: 50px;
|
||||
font-size: 1.1em;
|
||||
font: {
|
||||
size: 1.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,40 +5,42 @@ import { linkTo } from '@storybook/addon-links';
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { LogService } from '@ucap/logger';
|
||||
import { Company } from '@ucap/api-external';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { I18nService, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
|
||||
import { AuthenticationUiModule } from '../authentication-ui.module';
|
||||
|
||||
import { LoginComponent } from './login.component';
|
||||
|
||||
const actionsData = {
|
||||
login: action('login')
|
||||
};
|
||||
|
||||
const inputData = {
|
||||
companyList: [
|
||||
{ companyName: 'LG CNS', companyCode: 'GUC100' },
|
||||
{ companyName: 'LG UCAP', companyCode: 'GUC101' }
|
||||
] as Company[]
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'LoginComponent',
|
||||
title: 'ui-authentication::LoginComponent',
|
||||
component: LoginComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [BrowserModule, BrowserAnimationsModule, AuthenticationUiModule],
|
||||
providers: [
|
||||
{ provide: I18nService, useValue: new I18nService(new LogService({})) },
|
||||
{ provide: LogService, useValue: new LogService({}) },
|
||||
{ provide: I18nService, useClass: I18nService },
|
||||
{
|
||||
provide: UCAP_I18N_NAMESPACE,
|
||||
useValue: 'authentication'
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
excludeStories: /.*Data$/
|
||||
};
|
||||
|
||||
export const actionsData = {
|
||||
login: action('login')
|
||||
};
|
||||
|
||||
export const inputData = {
|
||||
companyList: [
|
||||
{ companyName: 'LG CNS', companyCode: 'GUC100' },
|
||||
{ companyName: 'LG UCAP', companyCode: 'GUC101' }
|
||||
] as Company[]
|
||||
]
|
||||
};
|
||||
|
||||
export const Default = () => ({
|
||||
|
@ -55,7 +57,6 @@ export const InputContents = () => ({
|
|||
companyList: inputData.companyList,
|
||||
companyCode: 'GUC100',
|
||||
loginId: 'test-loginid',
|
||||
// loginPw: '111111',
|
||||
login: actionsData.login
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
@import '~@ucap/ng-ui-material/material';
|
||||
|
||||
@mixin ucap-authentication-login-theme($theme) {
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$warn: map-get($theme, warn);
|
||||
$background: map-get($theme, background);
|
||||
$foreground: map-get($theme, foreground);
|
||||
|
||||
.ucap-authentication-login-container {
|
||||
border-color: mat-color($foreground, secondary-text);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin ucap-authentication-login-typography($config) {
|
||||
.ucap-authentication-login-container {
|
||||
font-family: mat-font-family($config);
|
||||
}
|
||||
}
|
|
@ -3,11 +3,13 @@
|
|||
"dest": "../../dist/ui-chat",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts",
|
||||
"styleIncludePaths": ["./src/assets/scss"],
|
||||
"umdModuleIds": {
|
||||
"ngx-perfect-scrollbar": "ngx-perfect-scrollbar",
|
||||
"@ucap/core": "@ucap/core",
|
||||
"@ucap/protocol-room": "@ucap/protocol-room",
|
||||
"@ucap/ng-logger": "@ucap/ng-logger",
|
||||
"@ucap/ng-i18n": "@ucap/ng-i18n",
|
||||
"@ucap/ng-ui": "@ucap/ng-ui"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@ucap/ng-ui-chat",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.9",
|
||||
"publishConfig": {
|
||||
"registry": "https://nexus.loafle.net/repository/npm-ucap/"
|
||||
},
|
||||
|
@ -11,8 +11,10 @@
|
|||
"@angular/material": "^9.0.0",
|
||||
"@ucap/core": "~0.0.1",
|
||||
"@ucap/protocol-room": "~0.0.1",
|
||||
"@ucap/uc-scss": "~0.0.1",
|
||||
"@ucap/ui-scss": "~0.0.1",
|
||||
"@ucap/ng-ui": "~0.0.1",
|
||||
"@ucap/ng-ui-material": "~0.0.1",
|
||||
"@ucap/ng-ui-organization": "~0.0.1",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
|
|
11
projects/ui-chat/scss-bundle.config.json
Normal file
11
projects/ui-chat/scss-bundle.config.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"bundlerOptions": {
|
||||
"entryFile": "./projects/ui-chat/src/assets/scss/_theme.scss",
|
||||
"rootDir": "./projects/ui-chat/src/assets/scss/",
|
||||
"outFile": "./dist/ui-chat/_theme.scss",
|
||||
"dedupeGlobs": [],
|
||||
"includePaths": [],
|
||||
"ignoreImports": ["~@ucap/.*", "~@angular/.*"],
|
||||
"logLevel": "silent"
|
||||
}
|
||||
}
|
2
projects/ui-chat/src/assets/scss/_theme.scss
Normal file
2
projects/ui-chat/src/assets/scss/_theme.scss
Normal file
|
@ -0,0 +1,2 @@
|
|||
@import '../../lib/components/room-expansion.component.theme.scss';
|
||||
@import '../../lib/components/room-list-item-01.component.theme.scss';
|
|
@ -28,8 +28,48 @@ import {
|
|||
RoomExpansionNodeDirective
|
||||
} from './components/room-expansion.component';
|
||||
import { RoomListItem01Component } from './components/room-list-item-01.component';
|
||||
import { InformationComponent } from './components/message-box/information.component';
|
||||
import { TextComponent } from './components/message-box/text.component';
|
||||
import { FileComponent } from './components/message-box/file.component';
|
||||
import { AttachFileComponent } from './components/message-box/attach-file.component';
|
||||
import { ImageComponent } from './components/message-box/image.component';
|
||||
import { VideoComponent } from './components/message-box/video.component';
|
||||
import { StickerComponent } from './components/message-box/sticker.component';
|
||||
import { MassComponent } from './components/message-box/mass.component';
|
||||
import { ScheduleComponent } from './components/message-box/schedule.component';
|
||||
import { VideoConferenceComponent } from './components/message-box/video-conference.component';
|
||||
import { TranslationComponent } from './components/message-box/translation.component';
|
||||
import { MassTranslationComponent } from './components/message-box/mass-translation.component';
|
||||
import { RecallComponent } from './components/message-box/recall.component';
|
||||
import { ReadHereComponent } from './components/message-box/read-here.component';
|
||||
import { DateSplitterComponent } from './components/message-box/date-splitter.component';
|
||||
import { SmsComponent } from './components/message-box/sms.component';
|
||||
import { ReplyComponent } from './components/message-box/reply.component';
|
||||
|
||||
const COMPONENTS = [RoomExpansionComponent, RoomListItem01Component];
|
||||
const COMPONENTS = [
|
||||
RoomExpansionComponent,
|
||||
RoomListItem01Component,
|
||||
|
||||
InformationComponent,
|
||||
TextComponent,
|
||||
FileComponent,
|
||||
AttachFileComponent,
|
||||
ImageComponent,
|
||||
VideoComponent,
|
||||
StickerComponent,
|
||||
MassComponent,
|
||||
ScheduleComponent,
|
||||
VideoConferenceComponent,
|
||||
TranslationComponent,
|
||||
MassTranslationComponent,
|
||||
RecallComponent,
|
||||
|
||||
ReadHereComponent,
|
||||
DateSplitterComponent,
|
||||
|
||||
SmsComponent,
|
||||
ReplyComponent
|
||||
];
|
||||
const DIALOGS = [];
|
||||
const PIPES = [];
|
||||
const DIRECTIVES = [RoomExpansionHeaderDirective, RoomExpansionNodeDirective];
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<div class="ucap-chat-message-box-attach-file" (click)="onClickOpenViewer()">
|
||||
<!--파일명에 따라 doc exe hwp ppt xls zip 으로 추가되고 나머지 파일 명은 file로 기간이 만료된 파일은 그뒤에 disable도 추가-->
|
||||
<!-- <div class="file-img" [ngClass]="fileInfo.FileExt"></div> -->
|
||||
<div [ngClass]="['mime-icon', 'light', 'ico-' + fileInfo.fileExt]">
|
||||
<div class="ico"></div>
|
||||
</div>
|
||||
<ul class="file-info">
|
||||
<li class="file-name">
|
||||
{{ fileInfo.fileName }}
|
||||
</li>
|
||||
<li class="date">
|
||||
{{ fileInfo.attachmentRegDate | ucapDate }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-box over">
|
||||
<ul *ngIf="!expired">
|
||||
<li>
|
||||
<button mat-button (click)="onClickSave()">
|
||||
저장
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button mat-button (click)="onClickSave()">
|
||||
폴더열기
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button mat-button (click)="onClickSave()">
|
||||
???
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="progress over">
|
||||
프로그레스 영역
|
||||
</div>
|
|
@ -0,0 +1,126 @@
|
|||
// $tablet-s-width: 768px;
|
||||
|
||||
// .bubble-main {
|
||||
// display: flex;
|
||||
// flex-direction: row;
|
||||
// padding: 14px;
|
||||
// min-width: 300px;
|
||||
// .file-img {
|
||||
// display: inline-flex;
|
||||
// width: 50px;
|
||||
// height: 50px;
|
||||
// float: left;
|
||||
// margin-right: 14px;
|
||||
// background-repeat: no-repeat;
|
||||
// &.doc {
|
||||
// background-image: url(/assets/images/file/icon_talk_doc.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_doc_d.png);
|
||||
// }
|
||||
// }
|
||||
// &.exe {
|
||||
// background-image: url(/assets/images/file/icon_talk_exe.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_exe_d.png);
|
||||
// }
|
||||
// }
|
||||
// &.file {
|
||||
// background-image: url(/assets/images/file/icon_talk_file.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_file_d.png);
|
||||
// }
|
||||
// }
|
||||
// &.hwp {
|
||||
// background-image: url(/assets/images/file/icon_talk_hwp.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_hwp_d.png);
|
||||
// }
|
||||
// }
|
||||
// &.ppt,
|
||||
// &.pptx {
|
||||
// background-image: url(/assets/images/file/icon_talk_ppt.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_ppt_d.png);
|
||||
// }
|
||||
// }
|
||||
// &.xls,
|
||||
// &.xlsm,
|
||||
// &.xlsx {
|
||||
// background-image: url(/assets/images/file/icon_talk_xls.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_xls_d.png);
|
||||
// }
|
||||
// }
|
||||
// &.zip {
|
||||
// background-image: url(/assets/images/file/icon_talk_zip.png);
|
||||
// &.disable {
|
||||
// background-image: url(/assets/images/file/icon_talk_doc_d.png);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .file-info {
|
||||
// display: inline-flex;
|
||||
// flex-direction: column;
|
||||
// text-align: left;
|
||||
// float: left;
|
||||
// line-height: 1.6em;
|
||||
// .file-name {
|
||||
// font-size: 1em;
|
||||
// font-weight: bold;
|
||||
// display: inline-flex;
|
||||
// }
|
||||
// .file-size {
|
||||
// display: inline-flex;
|
||||
// font-size: 11px;
|
||||
// color: #666666;
|
||||
// }
|
||||
// .file-ext {
|
||||
// font-size: 12px;
|
||||
// color: #848d95;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .btn-box {
|
||||
// width: 100%;
|
||||
// height: 40px;
|
||||
// border-top: 1px solid #dddddd;
|
||||
// display: flex;
|
||||
// width: 100%;
|
||||
// text-align: center;
|
||||
// font-size: 1em;
|
||||
// ul {
|
||||
// width: 100%;
|
||||
// li {
|
||||
// width: 50%;
|
||||
// height: 100%;
|
||||
// display: inline-block;
|
||||
// text-align: center;
|
||||
// align-items: center;
|
||||
// border-right: 1px solid #dddddd;
|
||||
// @media screen and (max-width: #{$tablet-s-width}) {
|
||||
// width: 30%;
|
||||
// }
|
||||
// &:last-child {
|
||||
// border-right: none;
|
||||
// @media screen and (max-width: #{$tablet-s-width}) {
|
||||
// width: 70%;
|
||||
// }
|
||||
// }
|
||||
// .mat-button {
|
||||
// width: 100%;
|
||||
// display: block;
|
||||
// height: 100%;
|
||||
// font-size: 1em;
|
||||
// }
|
||||
// }
|
||||
// &.expired {
|
||||
// li {
|
||||
// width: 100%;
|
||||
// white-space: nowrap;
|
||||
// color: #999999;
|
||||
// align-items: center;
|
||||
// line-height: 40px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -0,0 +1,28 @@
|
|||
/* tslint:disable:no-unused-variable */
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
|
||||
import { AttachFileComponent } from './attach-file.component';
|
||||
|
||||
describe('AttachFileComponent', () => {
|
||||
let component: AttachFileComponent;
|
||||
let fixture: ComponentFixture<AttachFileComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AttachFileComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AttachFileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { FileEventJson } from '@ucap/protocol-event';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-attach-file',
|
||||
templateUrl: './attach-file.component.html',
|
||||
styleUrls: ['./attach-file.component.scss']
|
||||
})
|
||||
export class AttachFileComponent implements OnInit {
|
||||
@Input()
|
||||
fileInfo: FileEventJson;
|
||||
|
||||
@Input()
|
||||
expired = false;
|
||||
|
||||
@Output()
|
||||
save = new EventEmitter<string>();
|
||||
|
||||
@Output()
|
||||
openViewer = new EventEmitter();
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
onClickSave() {
|
||||
this.save.emit('save');
|
||||
}
|
||||
onClickSaveAs() {
|
||||
this.save.emit('saveAs');
|
||||
}
|
||||
onClickOpenViewer() {
|
||||
this.openViewer.emit();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<div class="ucap-chat-message-box-date-splitter">
|
||||
<span class="date bg-warn-chat">{{
|
||||
this.message.sendDate | ucapDate: 'L dddd'
|
||||
}}</span>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DateSplitterComponent } from './date-splitter.component';
|
||||
|
||||
describe('Chat::MessageBox::DateSplitterComponent', () => {
|
||||
let component: DateSplitterComponent;
|
||||
let fixture: ComponentFixture<DateSplitterComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [DateSplitterComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DateSplitterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Info, EventJson } from '@ucap/protocol-event';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-date-splitter',
|
||||
templateUrl: './date-splitter.component.html',
|
||||
styleUrls: ['./date-splitter.component.scss']
|
||||
})
|
||||
export class DateSplitterComponent implements OnInit {
|
||||
@Input()
|
||||
message: Info<EventJson>;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<ng-container
|
||||
*ngIf="fileInfo && fileInfo.fileType"
|
||||
[ngSwitch]="fileInfo.fileType"
|
||||
class="ucap-chat-message-box-file"
|
||||
>
|
||||
<ucap-chat-message-box-attach-file
|
||||
*ngSwitchCase="FileType.File"
|
||||
[expired]="getExpiredFile()"
|
||||
(openViewer)="onClickFileViewer(fileInfo)"
|
||||
(save)="onSave($event)"
|
||||
>
|
||||
</ucap-chat-message-box-attach-file>
|
||||
|
||||
<ucap-chat-message-box-attach-file
|
||||
*ngSwitchCase="FileType.Sound"
|
||||
[expired]="getExpiredFile()"
|
||||
(openViewer)="onClickFileViewer(fileInfo)"
|
||||
(save)="onSave($event)"
|
||||
>
|
||||
</ucap-chat-message-box-attach-file>
|
||||
|
||||
<ucap-chat-message-box-image
|
||||
*ngSwitchCase="FileType.Image"
|
||||
[expired]="getExpiredFile()"
|
||||
(openViewer)="onClickFileViewer(fileInfo)"
|
||||
(save)="onSave($event)"
|
||||
></ucap-chat-message-box-image>
|
||||
|
||||
<ucap-chat-message-box-video
|
||||
*ngSwitchCase="FileType.Video"
|
||||
[expired]="getExpiredFile()"
|
||||
(openViewer)="onClickFileViewer(fileInfo)"
|
||||
(save)="onSave($event)"
|
||||
></ucap-chat-message-box-video>
|
||||
|
||||
<!--
|
||||
<ucap-chat-message-box-text
|
||||
*ngSwitchDefault
|
||||
[message]="message"
|
||||
></ucap-chat-message-box-text> -->
|
||||
</ng-container>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FileComponent } from './file.component';
|
||||
|
||||
describe('Chat::MessageBox::FileComponent', () => {
|
||||
let component: FileComponent;
|
||||
let fixture: ComponentFixture<FileComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [FileComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,71 @@
|
|||
import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
|
||||
import { FileType, Info, FileEventJson } from '@ucap/protocol-event';
|
||||
import { RoomInfo } from '@ucap/protocol-room';
|
||||
import { FileDownloadItem, StatusCode } from '@ucap/api';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-file',
|
||||
templateUrl: './file.component.html',
|
||||
styleUrls: ['./file.component.scss']
|
||||
})
|
||||
export class FileComponent implements OnInit {
|
||||
@Input()
|
||||
message: Info<FileEventJson>;
|
||||
|
||||
@Input()
|
||||
roomInfo: RoomInfo;
|
||||
|
||||
@Output()
|
||||
save = new EventEmitter<{
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}>();
|
||||
@Output()
|
||||
fileViewer = new EventEmitter<FileEventJson>();
|
||||
|
||||
fileInfo?: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
errorMessage?: string;
|
||||
FileType = FileType;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {
|
||||
if (StatusCode.Success === this.message.sentMessageJson.statusCode) {
|
||||
this.fileInfo = this.message.sentMessageJson;
|
||||
} else {
|
||||
this.errorMessage =
|
||||
this.message.sentMessageJson.errorMessage || '[Error] System Error!!';
|
||||
}
|
||||
|
||||
this.fileDownloadItem = new FileDownloadItem();
|
||||
}
|
||||
|
||||
getExpiredFile() {
|
||||
if (
|
||||
!!this.roomInfo &&
|
||||
this.roomInfo.expiredFileStdSeq <= this.message.seq
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
onClickFileViewer(fileInfo: FileEventJson) {
|
||||
if (!this.getExpiredFile()) {
|
||||
this.fileViewer.emit(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
onSave(value: string) {
|
||||
if (!this.getExpiredFile()) {
|
||||
this.save.emit({
|
||||
fileInfo: this.fileInfo,
|
||||
fileDownloadItem: this.fileDownloadItem,
|
||||
type: value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<div
|
||||
class="ucap-chat-message-box-image"
|
||||
(mouseenter)="mouseEnter($event)"
|
||||
(mouseleave)="mouseLeave($event)"
|
||||
>
|
||||
<div *ngIf="showExpired" class="expired-text">
|
||||
<span>만기된 파일입니다.</span>
|
||||
</div>
|
||||
<img [src]="fileInfo.thumbUrl" />
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ImageComponent } from './image.component';
|
||||
|
||||
describe('Chat::MessageBox::ImageComponent', () => {
|
||||
let component: ImageComponent;
|
||||
let fixture: ComponentFixture<ImageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ImageComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ImageComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FileEventJson } from '@ucap/protocol-event';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-image',
|
||||
templateUrl: './image.component.html',
|
||||
styleUrls: ['./image.component.scss']
|
||||
})
|
||||
export class ImageComponent implements OnInit {
|
||||
@Input()
|
||||
fileInfo: FileEventJson;
|
||||
@Input()
|
||||
expired = false;
|
||||
|
||||
showExpired = false;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
mouseEnter(event: MouseEvent): void {
|
||||
if (this.expired) {
|
||||
this.showExpired = true;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
mouseLeave(event: MouseEvent): void {
|
||||
if (this.expired) {
|
||||
this.showExpired = false;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
39
projects/ui-chat/src/lib/components/message-box/index.ts
Normal file
39
projects/ui-chat/src/lib/components/message-box/index.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { InformationComponent } from './information.component';
|
||||
import { TextComponent } from './text.component';
|
||||
import { FileComponent } from './file.component';
|
||||
import { AttachFileComponent } from './attach-file.component';
|
||||
import { ImageComponent } from './image.component';
|
||||
import { VideoComponent } from './video.component';
|
||||
import { StickerComponent } from './sticker.component';
|
||||
import { MassComponent } from './mass.component';
|
||||
import { ScheduleComponent } from './schedule.component';
|
||||
import { VideoConferenceComponent } from './video-conference.component';
|
||||
import { TranslationComponent } from './translation.component';
|
||||
import { MassTranslationComponent } from './mass-translation.component';
|
||||
import { RecallComponent } from './recall.component';
|
||||
import { SmsComponent } from './sms.component';
|
||||
import { ReplyComponent } from './reply.component';
|
||||
import { ReadHereComponent } from './read-here.component';
|
||||
import { DateSplitterComponent } from './date-splitter.component';
|
||||
|
||||
export const COMPONENTS = [
|
||||
InformationComponent,
|
||||
TextComponent,
|
||||
FileComponent,
|
||||
AttachFileComponent,
|
||||
ImageComponent,
|
||||
VideoComponent,
|
||||
StickerComponent,
|
||||
MassComponent,
|
||||
ScheduleComponent,
|
||||
VideoConferenceComponent,
|
||||
TranslationComponent,
|
||||
MassTranslationComponent,
|
||||
RecallComponent,
|
||||
|
||||
ReadHereComponent,
|
||||
DateSplitterComponent,
|
||||
|
||||
SmsComponent,
|
||||
ReplyComponent
|
||||
];
|
|
@ -0,0 +1,88 @@
|
|||
<div class="ucap-chat-message-box-information">
|
||||
<ng-container [ngSwitch]="message.type">
|
||||
<ng-container *ngSwitchCase="EventType.Join">
|
||||
{{ getI18nForSir(getOwnerForJoinEventJson()) }}이
|
||||
{{ getI18nForSir(getInviterForJoinEventJson()) }}을 초대했습니다.
|
||||
<!-- {{
|
||||
'chat.event.inviteToRoomWith'
|
||||
| translate
|
||||
: {
|
||||
owner: getI18nForSir(message.sentMessageJson.owner),
|
||||
inviter: getI18nForSir(message.sentMessageJson.inviter)
|
||||
}
|
||||
}} -->
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EventType.Exit">
|
||||
{{ message.sentMessage }}님이 퇴장하셨습니다.
|
||||
<!-- {{
|
||||
'chat.event.exitFromRoomWith'
|
||||
| translate: { exitor: message.sentMessage }
|
||||
}} -->
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EventType.ForcedExit">
|
||||
{{ message.exitForcingRequestUserName }}님이 {{ message.sentMessage }}님을
|
||||
퇴장 시키셨습니다.
|
||||
<!-- {{
|
||||
'chat.event.ejectedFromRoomWith'
|
||||
| translate
|
||||
: {
|
||||
requester: message.exitForcingRequestUserName,
|
||||
ejected: message.sentMessage
|
||||
}
|
||||
}} -->
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EventType.RenameRoom">
|
||||
{{ getRequesterForRenameRoom() }}님이 대화방명을 '{{
|
||||
getRoomNameForRenameRoom()
|
||||
}}'으로 변경하셨습니다.
|
||||
<!-- {{
|
||||
'chat.event.renamedRoomWith'
|
||||
| translate
|
||||
: {
|
||||
requester: message.sentMessageJson.requester,
|
||||
roomName: message.sentMessageJson.roomName
|
||||
}
|
||||
}} -->
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EventType.NotificationForTimerRoom">
|
||||
{{ message.sentMessage }}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EventType.GuideForRoomTimerChanged">
|
||||
{{ senderName }}님이 타이머를 설정하였습니다. ({{
|
||||
getCalcTimerForGuideForRoomTimerChanged()
|
||||
}})
|
||||
<!-- {{
|
||||
'chat.event.setTimerWith'
|
||||
| translate
|
||||
: {
|
||||
requester: senderName,
|
||||
timer: getCalcTimer(message.sentMessageJson.time * 1000)
|
||||
}
|
||||
}} -->
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="EventType.NotificationForiOSCapture">
|
||||
{{ message.sentMessage }}님이 대화내용을 캡쳐하였습니다.
|
||||
<!-- {{
|
||||
'chat.event.iosCapture'
|
||||
| translate
|
||||
: {
|
||||
requester: message.sentMessage
|
||||
}
|
||||
}} -->
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- <div class="ucap-chat-info-event">
|
||||
<div class="info bg-primary-chat">
|
||||
<strong class="text-warn-chat"
|
||||
>김나영, 김준혁,강은정,나정미,박미영,박정은, 박훈, 문영준, 이지은, 이진현,
|
||||
이현준, 임영찬, 임찬우, 정민우,정현욱, 최남진, 최영은, 최진우, 한고은,
|
||||
한정후, 한지민</strong
|
||||
>님이 초대되었습니다.
|
||||
</div>
|
||||
|
||||
<div class="chat-event others bg-accent-chat">
|
||||
자동 삭제 타이머가 10분으로 변경되었습니다.
|
||||
</div>
|
||||
</div> -->
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InformationComponent } from './information.component';
|
||||
|
||||
describe('Chat::MessageBox::InformationComponent', () => {
|
||||
let component: InformationComponent;
|
||||
let fixture: ComponentFixture<InformationComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [InformationComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(InformationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,134 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import {
|
||||
EventType,
|
||||
Info,
|
||||
EventJson,
|
||||
RenameRoomEventJson,
|
||||
GuideForRoomTimerChangedEventJson,
|
||||
JoinEventJson
|
||||
} from '@ucap/protocol-event';
|
||||
import { TranslateService } from '@ucap/ng-ui-organization';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-information',
|
||||
templateUrl: './information.component.html',
|
||||
styleUrls: ['./information.component.scss']
|
||||
})
|
||||
export class InformationComponent implements OnInit {
|
||||
@Input()
|
||||
message: Info<EventJson>;
|
||||
|
||||
@Input()
|
||||
senderName?: string;
|
||||
|
||||
EventType = EventType;
|
||||
|
||||
constructor(private translateService: TranslateService) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
getI18nForSir(names: string | string[]) {
|
||||
if (Array.isArray(names)) {
|
||||
const inviter: string[] = [];
|
||||
|
||||
// names.forEach((userName, idx) => {
|
||||
// inviter.push(
|
||||
// this.translateService.instant('common.messages.sirWith', {
|
||||
// sir: userName
|
||||
// })
|
||||
// );
|
||||
// });
|
||||
names.forEach((userName, idx) => {
|
||||
inviter.push(userName);
|
||||
});
|
||||
|
||||
return inviter.join(',');
|
||||
} else {
|
||||
// return this.translateService.instant('common.messages.sirWith', {
|
||||
// sir: names
|
||||
// });
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
getOwnerForJoinEventJson() {
|
||||
return (this.message.sentMessageJson as JoinEventJson).owner;
|
||||
}
|
||||
getInviterForJoinEventJson() {
|
||||
return (this.message.sentMessageJson as JoinEventJson).inviter;
|
||||
}
|
||||
getCalcTimerForGuideForRoomTimerChanged() {
|
||||
const millisec =
|
||||
Number(
|
||||
(this.message.sentMessageJson as GuideForRoomTimerChangedEventJson).time
|
||||
) * 1000;
|
||||
// const langs = this.translateService.instant([
|
||||
// 'common.units.hourFrom',
|
||||
// 'common.units.minute',
|
||||
// 'common.units.second'
|
||||
// ]);
|
||||
|
||||
// switch (millisec) {
|
||||
// case 5000:
|
||||
// return `5 ${langs['common.units.second']}`;
|
||||
// case 10000:
|
||||
// return `10 ${langs['common.units.second']}`;
|
||||
// case 30000:
|
||||
// return `30 ${langs['common.units.second']}`;
|
||||
// case 60000:
|
||||
// return `1 ${langs['common.units.minute']}`;
|
||||
// case 300000:
|
||||
// return `5 ${langs['common.units.minute']}`;
|
||||
// case 600000:
|
||||
// return `10 ${langs['common.units.minute']}`;
|
||||
// case 1800000:
|
||||
// return `30 ${langs['common.units.minute']}`;
|
||||
// case 3600000:
|
||||
// return `1 ${langs['common.units.hourFrom']}`;
|
||||
// case 21600000:
|
||||
// return `6 ${langs['common.units.hourFrom']}`;
|
||||
// case 43200000:
|
||||
// return `12 ${langs['common.units.hourFrom']}`;
|
||||
// case 86400000:
|
||||
// return `24 ${langs['common.units.hourFrom']}`;
|
||||
// default:
|
||||
// return `0 ${langs['common.units.second']}`;
|
||||
// }
|
||||
|
||||
const langs = ['초', '분', '시간'];
|
||||
|
||||
switch (millisec) {
|
||||
case 5000:
|
||||
return `5 ${langs[0]}`;
|
||||
case 10000:
|
||||
return `10 ${langs[0]}`;
|
||||
case 30000:
|
||||
return `30 ${langs[0]}`;
|
||||
case 60000:
|
||||
return `1 ${langs[1]}`;
|
||||
case 300000:
|
||||
return `5 ${langs[1]}`;
|
||||
case 600000:
|
||||
return `10 ${langs[1]}`;
|
||||
case 1800000:
|
||||
return `30 ${langs[1]}`;
|
||||
case 3600000:
|
||||
return `1 ${langs[2]}`;
|
||||
case 21600000:
|
||||
return `6 ${langs[2]}`;
|
||||
case 43200000:
|
||||
return `12 ${langs[2]}`;
|
||||
case 86400000:
|
||||
return `24 ${langs[2]}`;
|
||||
default:
|
||||
return `0 ${langs[0]}`;
|
||||
}
|
||||
}
|
||||
|
||||
getRequesterForRenameRoom() {
|
||||
return (this.message.sentMessageJson as RenameRoomEventJson).requester;
|
||||
}
|
||||
getRoomNameForRenameRoom() {
|
||||
return (this.message.sentMessageJson as RenameRoomEventJson).roomName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<div class="ucap-chat-message-box-mass-translation">
|
||||
<div
|
||||
*ngIf="!translationSimpleview || (!!translationSimpleview && !!isMe)"
|
||||
class="contents original"
|
||||
[innerHTML]="
|
||||
message.sentMessageJson.original
|
||||
| ucapSafeHtml
|
||||
| ucapLinefeedToHtml
|
||||
| ucapLinky
|
||||
"
|
||||
(contextmenu)="onContextMenuMessage($event, 'original')"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="!translationSimpleview || (!!translationSimpleview && !isMe)"
|
||||
class="contents translation"
|
||||
(contextmenu)="onContextMenuMessage($event, 'translation')"
|
||||
>
|
||||
<span class="language">{{ message.sentMessageJson.destLocale }}</span>
|
||||
<span
|
||||
[innerHTML]="
|
||||
message.sentMessageJson.translation
|
||||
| ucapSafeHtml
|
||||
| ucapLinefeedToHtml
|
||||
| ucapLinky
|
||||
"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<ul>
|
||||
<li>
|
||||
<button mat-button (click)="onClickMassDetail('O')">
|
||||
전체보기
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button mat-button (click)="onClickMassDetail('T')">
|
||||
<span class="language">{{ message.sentMessageJson.destLocale }}</span>
|
||||
번역보기
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MassTranslationComponent } from './mass-translation.component';
|
||||
|
||||
describe('Chat::MessageBox::MassTranslationComponent', () => {
|
||||
let component: MassTranslationComponent;
|
||||
let fixture: ComponentFixture<MassTranslationComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MassTranslationComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MassTranslationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,73 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
AfterViewInit,
|
||||
ElementRef,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
import { Info, MassTranslationEventJson } from '@ucap/protocol-event';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-mass-translation',
|
||||
templateUrl: './mass-translation.component.html',
|
||||
styleUrls: ['./mass-translation.component.scss']
|
||||
})
|
||||
export class MassTranslationComponent implements OnInit, AfterViewInit {
|
||||
@Input()
|
||||
message: Info<MassTranslationEventJson>;
|
||||
|
||||
@Input()
|
||||
translationSimpleview: boolean;
|
||||
|
||||
@Input()
|
||||
isMe: boolean;
|
||||
|
||||
@Output()
|
||||
massTranslationDetail = new EventEmitter<{
|
||||
message: Info<MassTranslationEventJson>;
|
||||
contentsType: string;
|
||||
}>();
|
||||
|
||||
@Output()
|
||||
contextMenu = new EventEmitter<{
|
||||
event: MouseEvent;
|
||||
type: string;
|
||||
}>();
|
||||
|
||||
@Output()
|
||||
openLink = new EventEmitter<string>();
|
||||
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (
|
||||
!!this.elementRef.nativeElement &&
|
||||
!!this.elementRef.nativeElement.querySelector('a')
|
||||
) {
|
||||
const elements = this.elementRef.nativeElement.querySelectorAll('a');
|
||||
elements.forEach((element) => {
|
||||
element.addEventListener('click', this.onClickEvent.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClickEvent(event: MouseEvent) {
|
||||
this.openLink.emit((event.target as HTMLAnchorElement).text);
|
||||
}
|
||||
|
||||
onClickMassDetail(contentsType: string) {
|
||||
this.massTranslationDetail.emit({
|
||||
message: this.message,
|
||||
contentsType
|
||||
});
|
||||
}
|
||||
|
||||
onContextMenuMessage(event: MouseEvent, type: string) {
|
||||
this.contextMenu.emit({ event, type });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<div class="ucap-chat-message-box-mass">
|
||||
<span
|
||||
class="content"
|
||||
[innerHTML]="content | ucapSafeHtml | ucapLinefeedToHtml | ucapLinky"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="detailButteonShow" class="btn-box">
|
||||
<button mat-button (click)="onClickDetailView()">
|
||||
전체보기
|
||||
</button>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MassComponent } from './mass.component';
|
||||
|
||||
describe('Chat::MessageBox::MassComponent', () => {
|
||||
let component: MassComponent;
|
||||
let fixture: ComponentFixture<MassComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MassComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MassComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,74 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
import { Info, MassTextEventJson } from '@ucap/protocol-event';
|
||||
import { StatusCode } from '@ucap/api';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-mass',
|
||||
templateUrl: './mass.component.html',
|
||||
styleUrls: ['./mass.component.scss']
|
||||
})
|
||||
export class MassComponent implements OnInit, AfterViewInit {
|
||||
@Input()
|
||||
message: Info<MassTextEventJson>;
|
||||
|
||||
@Output()
|
||||
massDetail = new EventEmitter<number>();
|
||||
|
||||
@Output()
|
||||
openLink = new EventEmitter<string>();
|
||||
|
||||
content: string;
|
||||
eventMassSeq: number;
|
||||
detailButteonShow = true;
|
||||
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {
|
||||
try {
|
||||
if (StatusCode.Success === this.message.sentMessageJson.statusCode) {
|
||||
this.content = this.message.sentMessageJson.content;
|
||||
} else {
|
||||
this.content =
|
||||
this.message.sentMessageJson.errorMessage || '[Error] System Error!!';
|
||||
this.detailButteonShow = false;
|
||||
}
|
||||
|
||||
if (!!this.message.sentMessageJson.massSeq) {
|
||||
this.eventMassSeq = this.message.sentMessageJson.massSeq;
|
||||
} else {
|
||||
this.detailButteonShow = false;
|
||||
}
|
||||
} catch (e) {
|
||||
this.detailButteonShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (
|
||||
!!this.elementRef.nativeElement &&
|
||||
!!this.elementRef.nativeElement.querySelector('a')
|
||||
) {
|
||||
const elements = this.elementRef.nativeElement.querySelectorAll('a');
|
||||
elements.forEach((element) => {
|
||||
element.addEventListener('click', this.onClickEvent.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClickEvent(event: MouseEvent) {
|
||||
this.openLink.emit((event.target as HTMLAnchorElement).text);
|
||||
}
|
||||
|
||||
onClickDetailView() {
|
||||
this.massDetail.emit(this.eventMassSeq);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<div class="ucap-chat-message-box-read-here">
|
||||
<span>여기까지 읽었습니다</span>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ReadHereComponent } from './read-here.component';
|
||||
|
||||
describe('Chat::MessageBox::ReadHereComponent', () => {
|
||||
let component: ReadHereComponent;
|
||||
let fixture: ComponentFixture<ReadHereComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ReadHereComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ReadHereComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-read-here',
|
||||
templateUrl: './read-here.component.html',
|
||||
styleUrls: ['./read-here.component.scss']
|
||||
})
|
||||
export class ReadHereComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<div class="ucap-chat-message-box-recall">
|
||||
<span class="icon-recall"><i class="material-icons">redo</i></span>
|
||||
<span class="recall-msg">회수된 메시지</span>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecallComponent } from './recall.component';
|
||||
|
||||
describe('Chat::MessageBox::RecallComponent', () => {
|
||||
let component: RecallComponent;
|
||||
let fixture: ComponentFixture<RecallComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [RecallComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecallComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-recall',
|
||||
templateUrl: './recall.component.html',
|
||||
styleUrls: ['./recall.component.scss']
|
||||
})
|
||||
export class RecallComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<div class="ucap-chat-message-box-reply">
|
||||
<div class="event-header" style="color: black;">
|
||||
<ul>
|
||||
<li class="sub-title">나에게 답장</li>
|
||||
<li class="parent-contents">
|
||||
올려 놓았습니다. 확인해 보시기 바랍니다.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<span class="language">→</span>
|
||||
네 감사합니다. 수고가 많으시네요. 오늘 중으로 확인해 보겠습니다.
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TextComponent } from './text.component';
|
||||
|
||||
describe('Chat::MessageBox::TextComponent', () => {
|
||||
let component: TextComponent;
|
||||
let fixture: ComponentFixture<TextComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TextComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TextComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-reply',
|
||||
templateUrl: './reply.component.html',
|
||||
styleUrls: ['./reply.component.scss']
|
||||
})
|
||||
export class ReplyComponent implements OnInit, AfterViewInit {
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngAfterViewInit(): void {}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<div class="ucap-chat-message-box-schedule">
|
||||
<div class="event-header" style="color: black;">
|
||||
<ng-container
|
||||
*ngIf="!!message.sentMessageJson && !!message.sentMessageJson.contents"
|
||||
>
|
||||
<ng-container [ngSwitch]="message.sentMessageJson.contents">
|
||||
<ng-container *ngSwitchCase="PlanContentType.New">
|
||||
{{ 'chat.event.scheduleTypeNew' | ucapI18n }}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="PlanContentType.Update">
|
||||
{{ 'chat.event.scheduleTypeUpdate' | ucapI18n }}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="PlanContentType.Delete">
|
||||
{{ 'chat.event.scheduleTypeDelete' | ucapI18n }}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<!-- {{ 'chat.event.scheduleTypeDefault' | translate }} -->
|
||||
{{ getAlertLeftTime() }}
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ul class="event-info">
|
||||
<li class="place">
|
||||
마곡 E14동 906호
|
||||
</li>
|
||||
<li class="date">
|
||||
2020.05.23 9:30 ~ 2020.05.23 11:30
|
||||
</li>
|
||||
<li class="event-content">
|
||||
{{ message.sentMessageJson.title }}
|
||||
{{ message.sentMessageJson.contents }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-box">
|
||||
<button mat-button>상세보기</button>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ScheduleComponent } from './schedule.component';
|
||||
|
||||
describe('Chat::MessageBox::ScheduleComponent', () => {
|
||||
let component: ScheduleComponent;
|
||||
let fixture: ComponentFixture<ScheduleComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ScheduleComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ScheduleComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,64 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Info, PlanEventJson, PlanContentType } from '@ucap/protocol-event';
|
||||
import { TranslateService } from '@ucap/ng-ui-organization';
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-schedule',
|
||||
templateUrl: './schedule.component.html',
|
||||
styleUrls: ['./schedule.component.scss']
|
||||
})
|
||||
export class ScheduleComponent implements OnInit {
|
||||
@Input()
|
||||
message: Info<PlanEventJson>;
|
||||
|
||||
PlanContentType = PlanContentType;
|
||||
date: any;
|
||||
endDate: any;
|
||||
|
||||
constructor(private translateService: TranslateService) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!!this.message && !!this.message.sentMessageJson) {
|
||||
if (!!this.message.sentMessageJson.date) {
|
||||
let strDate = this.message.sentMessageJson.date
|
||||
.replace(/ /g, '')
|
||||
.replace(/\n/g, '')
|
||||
.replace(/(\([월,화,수,목,금,토,일]\))/g, '');
|
||||
if (strDate.indexOf('오전') > -1) {
|
||||
strDate = strDate.replace('오전', ' ');
|
||||
} else if (strDate.indexOf('오후') > -1) {
|
||||
strDate = strDate.replace('오후', ' ');
|
||||
const arr = strDate.split(' ');
|
||||
const h = Number(arr[1].split(':')[0]) + 12;
|
||||
strDate = arr[0] + ' ' + h + ':' + arr[1].split(':')[1];
|
||||
}
|
||||
|
||||
this.date = moment(strDate).toDate();
|
||||
if (this.date === 'Invalid Date') {
|
||||
this.date = this.message.sentMessageJson.date.replace(/\n/g, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClickSave(): void {}
|
||||
|
||||
getAlertLeftTime(): string {
|
||||
let content = this.message.sentMessageJson.contents;
|
||||
if (content.indexOf('PLAN_CONTENTS_MINUTE') > -1) {
|
||||
content = content.replace('PLAN_CONTENTS_MINUTE', '분');
|
||||
} else if (content.indexOf('PLAN_CONTENTS_HOUR') > -1) {
|
||||
content = content.replace('PLAN_CONTENTS_HOUR', '시간');
|
||||
}
|
||||
|
||||
if (content.indexOf('PLAN_CONTENTS_AFTER') > -1) {
|
||||
content = content.replace('PLAN_CONTENTS_AFTER', ' 전 알림');
|
||||
}
|
||||
|
||||
content = '[이벤트] ' + content;
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<div class="ucap-chat-message-box-sms">
|
||||
<div class="event-header" style="color: black;">
|
||||
SMS
|
||||
</div>
|
||||
<div class="contents">
|
||||
SMS 내용 공간입니다. 내용을 보여주세요 SMS 내용 공간입니다. 내용을
|
||||
보여주세요 SMS 내용 공간입니다. 내용을 보여주세요
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TextComponent } from './text.component';
|
||||
|
||||
describe('Chat::MessageBox::TextComponent', () => {
|
||||
let component: TextComponent;
|
||||
let fixture: ComponentFixture<TextComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TextComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TextComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-sms',
|
||||
templateUrl: './sms.component.html',
|
||||
styleUrls: ['./sms.component.scss']
|
||||
})
|
||||
export class SmsComponent implements OnInit, AfterViewInit {
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngAfterViewInit(): void {}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<div class="ucap-chat-message-box-sticker">
|
||||
<ul>
|
||||
<li *ngIf="stickerUrl">
|
||||
<img [src]="stickerUrl" />
|
||||
</li>
|
||||
<li
|
||||
*ngIf="contents"
|
||||
[innerHTML]="contents | ucapSafeHtml | ucapLinefeedToHtml | ucapLinky"
|
||||
></li>
|
||||
</ul>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StickerComponent } from './sticker.component';
|
||||
|
||||
describe('Chat::MessageBox::StickerComponent', () => {
|
||||
let component: StickerComponent;
|
||||
let fixture: ComponentFixture<StickerComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StickerComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StickerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
EventEmitter,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { Info, StickerEventJson } from '@ucap/protocol-event';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-sticker',
|
||||
templateUrl: './sticker.component.html',
|
||||
styleUrls: ['./sticker.component.scss']
|
||||
})
|
||||
export class StickerComponent implements OnInit, AfterViewInit {
|
||||
@Input()
|
||||
message: Info<StickerEventJson>;
|
||||
|
||||
@Input()
|
||||
stickerUrl?: string;
|
||||
|
||||
@Input()
|
||||
stickerDefaultImagePath: string;
|
||||
|
||||
@Output()
|
||||
openLink = new EventEmitter<string>();
|
||||
|
||||
contents: string;
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!!this.message.sentMessageJson?.chat) {
|
||||
this.contents = this.message.sentMessageJson.chat;
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (
|
||||
!!this.elementRef.nativeElement &&
|
||||
!!this.elementRef.nativeElement.querySelector('a')
|
||||
) {
|
||||
const elements = this.elementRef.nativeElement.querySelectorAll('a');
|
||||
elements.forEach((element) => {
|
||||
element.addEventListener('click', this.onClickEvent.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClickEvent(event: MouseEvent) {
|
||||
this.openLink.emit((event.target as HTMLAnchorElement).text);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<div class="ucap-chat-message-box-text">
|
||||
<span [innerHTML]="message.sentMessage | ucapSafeHtml | ucapLinky"></span>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TextComponent } from './text.component';
|
||||
|
||||
describe('Chat::MessageBox::TextComponent', () => {
|
||||
let component: TextComponent;
|
||||
let fixture: ComponentFixture<TextComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TextComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TextComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ElementRef,
|
||||
AfterViewInit,
|
||||
Output,
|
||||
EventEmitter
|
||||
} from '@angular/core';
|
||||
import { Info, EventJson } from '@ucap/protocol-event';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-text',
|
||||
templateUrl: './text.component.html',
|
||||
styleUrls: ['./text.component.scss']
|
||||
})
|
||||
export class TextComponent implements OnInit, AfterViewInit {
|
||||
@Input()
|
||||
message: Info<EventJson>;
|
||||
|
||||
@Output()
|
||||
openLink = new EventEmitter<string>();
|
||||
|
||||
constructor(private elementRef: ElementRef) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (
|
||||
!!this.elementRef.nativeElement &&
|
||||
!!this.elementRef.nativeElement.querySelector('a')
|
||||
) {
|
||||
const elements = this.elementRef.nativeElement.querySelectorAll('a');
|
||||
elements.forEach((element) => {
|
||||
element.addEventListener('click', this.onClickEvent.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClickEvent(event: MouseEvent) {
|
||||
this.openLink.emit((event.target as HTMLAnchorElement).text);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<div class="ucap-chat-message-box-translation">
|
||||
<div class="sticker" *ngIf="!!stickerUrl && stickerUrl.trim().length > 0">
|
||||
<img [src]="stickerUrl" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="!translationSimpleview || (!!translationSimpleview && !!isMe)"
|
||||
class="original"
|
||||
[innerHTML]="message.sentMessageJson.original | ucapLinky"
|
||||
(contextmenu)="onContextMenuMessage($event, 'original')"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="!translationSimpleview || (!!translationSimpleview && !isMe)"
|
||||
class="translation"
|
||||
(contextmenu)="onContextMenuMessage($event, 'translation')"
|
||||
>
|
||||
<span class="language">{{ message.sentMessageJson.locale }}</span>
|
||||
<span [innerHTML]="message.sentMessageJson.translation | ucapLinky"> </span>
|
||||
</div>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user