Compare commits

...

29 Commits

Author SHA1 Message Date
c25639b40c Suchparameter in URL 2021-09-27 17:50:01 +02:00
a2048d0eb9 Merge pull request 'Überarbeitung Suchansicht' (#37) from feature-search into main
Reviewed-on: kompetenzinventar/ki-frontend#37
2021-09-23 16:57:31 +02:00
b19a770d61 no more search in navbar 2021-09-23 16:57:09 +02:00
8098c54c06 Merge branch 'feature-search' of git.wtf-eg.de:kompetenzinventar/ki-frontend into feature-search 2021-09-22 00:09:27 +02:00
73847022e2 implement search layout #32 #33 #35 2021-09-22 00:01:17 +02:00
93cb302ca7 implement search layout #32 #33 #35 2021-09-21 23:58:42 +02:00
fcbf3ee796 Merge branch 'sonntag' into main 2021-09-20 16:45:54 +02:00
fee786f1c8 bessere anzeige search 2021-09-20 16:44:44 +02:00
b190a3764b Merge pull request 'Sonntagsarbeiten' (#30) from sonntag into main
Reviewed-on: kompetenzinventar/ki-frontend#30
2021-09-20 11:15:20 +02:00
a408cae686 introduce vuex 2021-09-19 17:31:46 +02:00
94d2a98b96 apply navbar style #15 2021-09-19 16:38:43 +02:00
a1546849c8 apply login view design #29 2021-09-19 16:01:45 +02:00
a13314327c replace axios by fetch #13 2021-09-19 15:55:18 +02:00
ebb0783103 add reuse compliance #5 2021-09-19 13:04:03 +02:00
6a5b468bb2 fix vue 404 #26 2021-09-19 12:19:40 +02:00
ec8bc47ec7 style footer #14 2021-09-19 11:50:30 +02:00
c73534f448 update boostrap 2021-09-19 10:42:59 +02:00
94b1d52fbb #17 fix anzeige 2021-09-15 21:15:09 +02:00
d1026fafbb [BUG] Auch leere Kontakte können editiert sein 2021-09-15 21:06:53 +02:00
46d4c596e9 Neuer Tab für Issues 2021-09-15 21:02:51 +02:00
96cfd18d83 #27 2021-09-15 20:54:08 +02:00
4cb045d29f Merge branch 'main' of git.wtf-eg.de:kompetenzinventar/ki-frontend into main 2021-09-13 18:40:57 +02:00
2cf781b11d Anzeige mein Profil 2021-09-13 18:40:50 +02:00
b1f28e5d55 Merge pull request 'Mehr Prosa über die Aufteilung und wie man mitmachen kann' (#25) from 64bit/ki-frontend:mitmachen into main
Reviewed-on: kompetenzinventar/ki-frontend#25
2021-09-13 11:07:41 +02:00
b40913b331 Mehr Prosa über die Aufteilung und wie man mitmachen kann 2021-09-13 10:17:45 +02:00
5b3252ec98 Merge branch 'main' of git.wtf-eg.de:kompetenzinventar/ki-frontend into main 2021-08-18 22:59:50 +02:00
f0ef4e7f13 #13 2021-08-18 22:59:44 +02:00
3fbc64d9f8 Merge pull request 'editorconfig' (#24) from feature-editorconfig into main
Reviewed-on: kompetenzinventar/ki-frontend#24
2021-08-18 14:52:17 +02:00
513d204d58 #17 #16 2021-08-18 14:34:28 +02:00
48 changed files with 1364 additions and 585 deletions

View File

@ -7,6 +7,8 @@ type: docker
name: default
steps:
- name: reuse
image: fsfe/reuse:latest
- name: docker-publish
image: plugins/docker
settings:

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
jsconfig.json

View File

@ -3,8 +3,26 @@ Upstream-Name: ki-frontend
Upstream-Contact: Scammo <kontakt@samuelbrinkmann.de>
Source: https://git.wtf-eg.de/kompetenzinventar/ki-frontend
# Sample paragraph, commented out:
#
# Files: src/*
# Copyright: $YEAR $NAME <$CONTACT>
# License: ...
Files: package.json package-lock.json
Copyright: WTF Kooperative eG <https://wtf-eg.de/>
License: AGPL-3.0-or-later
Files: .browserslistrc .dockerignore .eslintrc.js .gitignore
Copyright: WTF Kooperative eG <https://wtf-eg.de/>
License: AGPL-3.0-or-later
Files: src/assets/img/wtf*
Copyright: WTF Kooperative eG <https://wtf-eg.de/>
License: LicenseRef-WTF
Files: src/assets/language_level.json src/assets/skill_level.json
Copyright: WTF Kooperative eG <https://wtf-eg.de/>
License: AGPL-3.0-or-later
Files: public/img/bootstrap-icons-1.5.0/*
Copyright: Copyright (c) 2019-2020 The Bootstrap Authors
License: MIT
Files: public/fonts/Lato*
Copyright: 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com)
License: OFL-1.1-RFN

View File

@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
FROM node:14-alpine as builder
COPY . ./
@ -8,3 +12,4 @@ RUN npm ci && npm run build
FROM nginx as ki-frontend
COPY --from=builder /dist/ /usr/share/nginx/html/
COPY etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf

View File

@ -0,0 +1 @@
Alle Rechte vorbehalten

View File

@ -1,9 +0,0 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

43
LICENSES/OFL-1.1-RFN.txt Normal file
View File

@ -0,0 +1,43 @@
SIL OPEN FONT LICENSE
Version 1.1 - 26 February 2007
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting, or substituting — in part or in whole — any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -1,8 +1,40 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
# ki-frontend
[![Build Status](https://drone.wtf-eg.de/api/badges/kompetenzinventar/ki-frontend/status.svg)](https://drone.wtf-eg.de/kompetenzinventar/ki-frontend)
[![REUSE status](https://api.reuse.software/badge/git.wtf-eg.de/kompetenzinventar/ki-frontend)](https://api.reuse.software/info/git.wtf-eg.de/kompetenzinventar/ki-frontend)
Vue3 Projekt:
## Über
Dieses Repo enthält das Frontend des Projekts Kompentenzinventar - einer Webapplikation zur Erfassung von Userprofilen für die WTF eG.
Implementiert ist das Frontend mit Vue3.
### Mitmachen
Du kannst gerne bei der Entwicklung des Kompetenzinventars mitmachen.
- Fehler oder fehlende Funktionen erfassen. Bitte direkt über die [Issues](https://git.wtf-eg.de/kompetenzinventar/ki-frontend/issues) in Gitea.
- Dokumentation oder Implementierung verbessern. Bitte forke hierzu das Projekt, branche von `main` ab und erstelle dann einen [Pull Request](https://git.wtf-eg.de/kompetenzinventar/ki-frontend/pulls).
### Kommunikation
Folgende Kanäle gibt es für die Kommunikation über das Kompetenzinventar:
- Die [Issues](https://git.wtf-eg.de/kompetenzinventar/ki-frontend/issues) im WTF Gitea.
- Den Bereich [AG Entwicklung](https://forum.wtf-eg.de/c/interna/ag-entwicklung/21) im WTF Forum.
- Einen Raum in Matrix. Zutritt per Einladung, frlan lädt ein, eine einfache PN im Forum reicht.
### Repos
* [ki-backend](https://git.wtf-eg.de/kompetenzinventar/ki-backend) enthält das Backend
* **[ki-frontend](https://git.wtf-eg.de/kompetenzinventar/ki-frontend)** (dieses Repo) enthält das Frontend
* Weitere Repositories befinden sich in der Gitea Organisation [Kompetenzinventar](https://git.wtf-eg.de/kompetenzinventar).
## Project setup
```

View File

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'

View File

@ -0,0 +1,49 @@
# SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}

99
package-lock.json generated
View File

@ -13,16 +13,17 @@
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"axios": "^0.21.1",
"babel-eslint": "^10.1.0",
"bootstrap": "^5.0.1",
"bootstrap-icons": "^1.5.0",
"core-js": "^3.6.5",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0",
"sass": "^1.37.5",
"sass-loader": "^10.2.0",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
"vue-router": "^4.0.0-0",
"vuex": "^4.0.2"
}
},
"node_modules/@babel/code-frame": {
@ -1209,6 +1210,17 @@
"node": ">= 6"
}
},
"node_modules/@popperjs/core": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.1.tgz",
"integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==",
"dev": true,
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@soda/friendly-errors-webpack-plugin": {
"version": "1.8.0",
"resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.8.0.tgz?cache=0&sync_timestamp=1607927625608&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40soda%2Ffriendly-errors-webpack-plugin%2Fdownload%2F%40soda%2Ffriendly-errors-webpack-plugin-1.8.0.tgz",
@ -2576,15 +2588,6 @@
"integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
"dev": true
},
"node_modules/axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.10.0"
}
},
"node_modules/babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz",
@ -2840,10 +2843,26 @@
"dev": true
},
"node_modules/bootstrap": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.1.tgz",
"integrity": "sha512-Fl79+wsLOZKoiU345KeEaWD0ik8WKRI5zm0YSPj2oF1Qr+BO7z0fco6GbUtqjoG1h4VI89PeKJnMsMMVQdKKTw==",
"dev": true
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.1.tgz",
"integrity": "sha512-/jUa4sSuDZWlDLQ1gwQQR8uoYSvLJzDd8m5o6bPKh3asLAMYVZKdRCjb1joUd5WXf0WwCNzd2EjwQQhupou0dA==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
},
"peerDependencies": {
"@popperjs/core": "^2.10.1"
}
},
"node_modules/bootstrap-icons": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.5.0.tgz",
"integrity": "sha512-44feMc7DE1Ccpsas/1wioN8ewFJNquvi5FewA06wLnqct7CwMdGDVy41ieHaacogzDqLfG8nADIvMNp9e4bfbA==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
@ -13327,6 +13346,18 @@
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
"dev": true
},
"node_modules/vuex": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
"integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
"dev": true,
"dependencies": {
"@vue/devtools-api": "^6.0.0-beta.11"
},
"peerDependencies": {
"vue": "^3.0.2"
}
},
"node_modules/watchpack": {
"version": "1.7.5",
"resolved": "https://registry.nlark.com/watchpack/download/watchpack-1.7.5.tgz?cache=0&sync_timestamp=1621437900992&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwatchpack%2Fdownload%2Fwatchpack-1.7.5.tgz",
@ -15629,6 +15660,13 @@
"integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=",
"dev": true
},
"@popperjs/core": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.1.tgz",
"integrity": "sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==",
"dev": true,
"peer": true
},
"@soda/friendly-errors-webpack-plugin": {
"version": "1.8.0",
"resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.8.0.tgz?cache=0&sync_timestamp=1607927625608&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40soda%2Ffriendly-errors-webpack-plugin%2Fdownload%2F%40soda%2Ffriendly-errors-webpack-plugin-1.8.0.tgz",
@ -16887,15 +16925,6 @@
"integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
"dev": true
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"dev": true,
"requires": {
"follow-redirects": "^1.10.0"
}
},
"babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz",
@ -17130,9 +17159,16 @@
"dev": true
},
"bootstrap": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.1.tgz",
"integrity": "sha512-Fl79+wsLOZKoiU345KeEaWD0ik8WKRI5zm0YSPj2oF1Qr+BO7z0fco6GbUtqjoG1h4VI89PeKJnMsMMVQdKKTw==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.1.tgz",
"integrity": "sha512-/jUa4sSuDZWlDLQ1gwQQR8uoYSvLJzDd8m5o6bPKh3asLAMYVZKdRCjb1joUd5WXf0WwCNzd2EjwQQhupou0dA==",
"dev": true,
"requires": {}
},
"bootstrap-icons": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.5.0.tgz",
"integrity": "sha512-44feMc7DE1Ccpsas/1wioN8ewFJNquvi5FewA06wLnqct7CwMdGDVy41ieHaacogzDqLfG8nADIvMNp9e4bfbA==",
"dev": true
},
"brace-expansion": {
@ -25933,6 +25969,15 @@
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
"dev": true
},
"vuex": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
"integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
"dev": true,
"requires": {
"@vue/devtools-api": "^6.0.0-beta.11"
}
},
"watchpack": {
"version": "1.7.5",
"resolved": "https://registry.nlark.com/watchpack/download/watchpack-1.7.5.tgz?cache=0&sync_timestamp=1621437900992&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwatchpack%2Fdownload%2Fwatchpack-1.7.5.tgz",

View File

@ -12,15 +12,16 @@
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"axios": "^0.21.1",
"babel-eslint": "^10.1.0",
"bootstrap": "^5.0.1",
"bootstrap-icons": "^1.5.0",
"core-js": "^3.6.5",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0",
"sass": "^1.37.5",
"sass-loader": "^10.2.0",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
"vue-router": "^4.0.0-0",
"vuex": "^4.0.2"
}
}

BIN
public/apple-touch-icon.png (Stored with Git LFS)

Binary file not shown.

View File

@ -1,4 +1,7 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
window.ki = {
apiUrl: 'http://localhost:5000'
}

View File

@ -1,4 +1,7 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
window.ki = {
apiUrl: 'http://localhost:13338'
}

BIN
public/favicon-96x96.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +0,0 @@
SPDX-License-Identifier: MIT

View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
</svg>

Before

Width:  |  Height:  |  Size: 548 B

View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
<path d="M8 0a1 1 0 0 1 1 1v6h6a1 1 0 1 1 0 2H9v6a1 1 0 1 1-2 0V9H1a1 1 0 0 1 0-2h6V1a1 1 0 0 1 1-1z"/>
</svg>

Before

Width:  |  Height:  |  Size: 238 B

View File

@ -1 +0,0 @@
SPDX-License-Identifier: MIT

View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
</svg>

Before

Width:  |  Height:  |  Size: 331 B

View File

@ -1 +0,0 @@
SPDX-License-Identifier: MIT

View File

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
</svg>

Before

Width:  |  Height:  |  Size: 573 B

View File

@ -1 +0,0 @@
SPDX-License-Identifier: MIT

View File

@ -1,3 +1,9 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<!DOCTYPE html>
<html lang="de">
<head>

View File

@ -1,115 +1,25 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="alert alert-success text-center mb-0" role="alert">
Willkommen beim Alpha-Test!
<a href="https://git.wtf-eg.de/kompetenzinventar/ki-frontend/issues/new">Problem gefunden? Bitte hier ein Issue anlegen.</a>
</div>
<header v-if="this.$route.path.includes('/s/')">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">KI</a>
<button
@click="showMobileNavbar = !showMobileNavbar"
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div
class="collapse navbar-collapse"
:class="{
show: showMobileNavbar,
}"
id="navbarSupportedContent"
>
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<router-link
class="nav-link"
:to="{ path: `/s/search` }"
active-class="active"
>Suche</router-link
>
</li>
<li class="nav-item">
<router-link
class="nav-link"
:to="{ path: `/s/profile/${memberId}` }"
active-class="active"
>Mein Profil</router-link
>
</li>
<li class="nav-item">
<router-link
class="nav-link"
:to="{ path: `/s/profile-edit` }"
active-class="active"
>Bearbeiten</router-link
>
</li>
<li class="nav-item">
<button class="btn btn-outline-danger" @click="logout()">
Logout
</button>
<a class="nav-link active" aria-current="page" href="#"></a>
</li>
</ul>
<form class="d-flex" @submit.prevent="searchRedirect()">
<input
class="form-control me-2"
v-model="searchText"
type="search"
placeholder="Profile durchsuchen"
aria-label="Search"
/>
<button
class="btn btn-outline-primary"
type="submit"
>
<img
src="/img/bootstrap-icons-1.5.0/search.svg"
alt="Suche Icon"
/>
</button>
</form>
</div>
</div>
</nav>
<Navbar />
</header>
<router-view />
<footer>
<a href="https://wtf-eg.de/impressum/" class="m-4">Impressum</a>
<a href="https://wtf-eg.de/datenschutz/" class="m-4">Datenschutz</a>
<a href="https://git.wtf-eg.de/kompetenzinventar" class="m-4">git(ea)</a>
<a href="https://git.wtf-eg.de/kompetenzinventar/ki-frontend/issues/new" class="m-4">Problem melden</a>
</footer>
<router-view :key="$route.fullPath" />
<Footer />
</template>
<script>
import Footer from '@/components/Footer'
import Navbar from '@/components/Navbar'
export default {
name: "App",
data() {
return {
showMobileNavbar: false,
memberId: null,
searchText: "",
};
},
created() {
this.memberId = localStorage.getItem("user_id");
},
methods: {
logout() {
localStorage.clear();
this.$router.push({ path: "/" });
},
searchRedirect() {
this.$router.push({ path: `/s/search?text`, query: { query: this.searchText } } );
},
},
name: 'App',
components: {
Footer,
Navbar,
}
};
</script>

View File

@ -1,10 +1,23 @@
/*
* SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@import "variables";
@import "bootstrap/scss/bootstrap";
.container{
min-height: calc(100vh - 70px - 24px);
.bg-wtf {
background-image: url(../assets/img/wtf-header-bg.jpg);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
.btn-primary {
color: #fff !important;
}
.search-card{
height: 100%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1476 617" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Background" transform="matrix(1,0,0,1,-184.291,-861.078)">
<rect x="184.291" y="861.078" width="1475.62" height="616.639" style="fill:none;"/>
</g>
<g id="Logo" transform="matrix(1,0,0,1,-184.236,-860.997)">
<g id="WTF-Koorperative-eG" serif:id="WTF Koorperative eG">
<g id="eG" transform="matrix(4.16667,0,0,4.16667,-389.557,-181.762)">
<g transform="matrix(15.962,0,0,15.962,431.653,372.57)">
<path d="M0.288,-0.434C0.271,-0.434 0.255,-0.431 0.241,-0.424C0.227,-0.417 0.214,-0.407 0.202,-0.395C0.191,-0.383 0.181,-0.368 0.172,-0.351C0.164,-0.334 0.157,-0.315 0.152,-0.295C0.193,-0.3 0.227,-0.306 0.252,-0.313C0.277,-0.32 0.296,-0.327 0.31,-0.335C0.324,-0.343 0.333,-0.352 0.337,-0.361C0.342,-0.37 0.344,-0.38 0.344,-0.39C0.344,-0.395 0.343,-0.4 0.341,-0.405C0.339,-0.41 0.335,-0.415 0.331,-0.419C0.326,-0.423 0.32,-0.427 0.313,-0.43C0.306,-0.433 0.298,-0.434 0.288,-0.434ZM0.142,-0.209C0.142,-0.128 0.176,-0.088 0.244,-0.088C0.259,-0.088 0.272,-0.089 0.283,-0.092C0.294,-0.095 0.304,-0.098 0.313,-0.103C0.321,-0.107 0.329,-0.111 0.336,-0.116C0.343,-0.121 0.349,-0.126 0.355,-0.13C0.361,-0.134 0.366,-0.137 0.372,-0.14C0.378,-0.143 0.384,-0.144 0.391,-0.144C0.395,-0.144 0.398,-0.143 0.402,-0.141C0.406,-0.139 0.41,-0.136 0.413,-0.133L0.444,-0.095C0.426,-0.077 0.409,-0.062 0.392,-0.049C0.375,-0.036 0.358,-0.025 0.34,-0.017C0.322,-0.009 0.304,-0.003 0.284,0.002C0.264,0.006 0.243,0.008 0.22,0.008C0.19,0.008 0.163,0.002 0.139,-0.008C0.114,-0.018 0.093,-0.032 0.076,-0.051C0.059,-0.069 0.045,-0.092 0.036,-0.118C0.026,-0.144 0.022,-0.173 0.022,-0.206C0.022,-0.233 0.024,-0.259 0.03,-0.285C0.036,-0.311 0.045,-0.336 0.056,-0.359C0.067,-0.382 0.08,-0.404 0.096,-0.424C0.112,-0.443 0.13,-0.46 0.15,-0.475C0.17,-0.489 0.193,-0.5 0.217,-0.508C0.241,-0.516 0.267,-0.52 0.295,-0.52C0.321,-0.52 0.345,-0.516 0.365,-0.509C0.385,-0.501 0.402,-0.491 0.415,-0.479C0.429,-0.467 0.439,-0.453 0.446,-0.438C0.452,-0.423 0.456,-0.408 0.456,-0.394C0.456,-0.371 0.451,-0.35 0.442,-0.331C0.433,-0.312 0.416,-0.295 0.393,-0.28C0.369,-0.265 0.337,-0.252 0.297,-0.241C0.256,-0.23 0.204,-0.222 0.142,-0.216L0.142,-0.209Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(15.962,0,0,15.962,440.065,372.57)">
<path d="M0.41,-0.361L0.635,-0.361L0.599,-0.07C0.562,-0.043 0.522,-0.024 0.48,-0.011C0.438,0.002 0.389,0.008 0.335,0.008C0.291,0.008 0.25,0 0.214,-0.016C0.178,-0.032 0.147,-0.054 0.121,-0.083C0.095,-0.111 0.076,-0.145 0.062,-0.184C0.048,-0.223 0.041,-0.266 0.041,-0.313C0.041,-0.353 0.045,-0.392 0.054,-0.428C0.063,-0.465 0.076,-0.498 0.092,-0.53C0.109,-0.561 0.129,-0.588 0.152,-0.613C0.175,-0.638 0.201,-0.659 0.23,-0.677C0.259,-0.694 0.29,-0.708 0.323,-0.717C0.357,-0.726 0.392,-0.731 0.429,-0.731C0.458,-0.731 0.484,-0.728 0.508,-0.723C0.532,-0.718 0.554,-0.711 0.573,-0.702C0.592,-0.693 0.61,-0.683 0.625,-0.671C0.64,-0.659 0.654,-0.646 0.666,-0.633L0.624,-0.579C0.617,-0.569 0.609,-0.563 0.6,-0.561C0.59,-0.559 0.58,-0.561 0.57,-0.568C0.56,-0.574 0.551,-0.581 0.541,-0.587C0.531,-0.593 0.521,-0.599 0.509,-0.604C0.498,-0.608 0.485,-0.612 0.47,-0.616C0.455,-0.619 0.438,-0.62 0.419,-0.62C0.383,-0.62 0.349,-0.613 0.32,-0.598C0.29,-0.584 0.264,-0.563 0.242,-0.537C0.22,-0.51 0.204,-0.478 0.192,-0.441C0.18,-0.404 0.174,-0.363 0.174,-0.317C0.174,-0.282 0.178,-0.251 0.187,-0.224C0.196,-0.197 0.208,-0.173 0.224,-0.155C0.24,-0.135 0.259,-0.121 0.282,-0.111C0.304,-0.101 0.329,-0.095 0.357,-0.096C0.384,-0.095 0.408,-0.098 0.429,-0.103C0.45,-0.108 0.47,-0.116 0.489,-0.126L0.505,-0.263L0.425,-0.263C0.417,-0.263 0.41,-0.265 0.406,-0.27C0.402,-0.274 0.4,-0.28 0.401,-0.287L0.41,-0.361Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
<g id="Kooperative" transform="matrix(4.16667,0,0,4.16667,896.411,1370.07)">
<g transform="matrix(18.037,0,0,18.037,0,0)">
<path d="M0.786,-0.365C0.786,-0.312 0.776,-0.263 0.758,-0.218C0.74,-0.172 0.715,-0.133 0.682,-0.099C0.649,-0.066 0.609,-0.04 0.562,-0.021C0.516,-0.002 0.464,0.008 0.408,0.008C0.351,0.008 0.299,-0.002 0.253,-0.021C0.206,-0.04 0.166,-0.066 0.133,-0.099C0.1,-0.133 0.074,-0.172 0.056,-0.218C0.038,-0.263 0.029,-0.312 0.029,-0.365C0.029,-0.417 0.038,-0.466 0.056,-0.512C0.074,-0.557 0.1,-0.596 0.133,-0.63C0.166,-0.663 0.206,-0.689 0.253,-0.708C0.299,-0.727 0.351,-0.737 0.408,-0.737C0.464,-0.737 0.516,-0.727 0.562,-0.708C0.609,-0.689 0.649,-0.662 0.682,-0.629C0.715,-0.596 0.74,-0.556 0.758,-0.511C0.776,-0.466 0.786,-0.417 0.786,-0.365ZM0.613,-0.365C0.613,-0.401 0.608,-0.433 0.599,-0.462C0.589,-0.491 0.576,-0.515 0.558,-0.535C0.541,-0.555 0.519,-0.57 0.494,-0.581C0.469,-0.592 0.44,-0.597 0.408,-0.597C0.375,-0.597 0.346,-0.592 0.32,-0.581C0.295,-0.57 0.273,-0.555 0.256,-0.535C0.238,-0.515 0.225,-0.491 0.216,-0.462C0.206,-0.433 0.202,-0.401 0.202,-0.365C0.202,-0.328 0.206,-0.296 0.216,-0.267C0.225,-0.238 0.238,-0.214 0.256,-0.194C0.273,-0.173 0.295,-0.158 0.32,-0.148C0.346,-0.137 0.375,-0.132 0.408,-0.132C0.44,-0.132 0.469,-0.137 0.494,-0.148C0.519,-0.158 0.541,-0.173 0.558,-0.194C0.576,-0.214 0.589,-0.238 0.599,-0.267C0.608,-0.296 0.613,-0.328 0.613,-0.365Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,14.6911,0)">
<path d="M0.786,-0.365C0.786,-0.312 0.776,-0.263 0.758,-0.218C0.74,-0.172 0.715,-0.133 0.682,-0.099C0.649,-0.066 0.609,-0.04 0.562,-0.021C0.516,-0.002 0.464,0.008 0.408,0.008C0.351,0.008 0.299,-0.002 0.253,-0.021C0.206,-0.04 0.166,-0.066 0.133,-0.099C0.1,-0.133 0.074,-0.172 0.056,-0.218C0.038,-0.263 0.029,-0.312 0.029,-0.365C0.029,-0.417 0.038,-0.466 0.056,-0.512C0.074,-0.557 0.1,-0.596 0.133,-0.63C0.166,-0.663 0.206,-0.689 0.253,-0.708C0.299,-0.727 0.351,-0.737 0.408,-0.737C0.464,-0.737 0.516,-0.727 0.562,-0.708C0.609,-0.689 0.649,-0.662 0.682,-0.629C0.715,-0.596 0.74,-0.556 0.758,-0.511C0.776,-0.466 0.786,-0.417 0.786,-0.365ZM0.613,-0.365C0.613,-0.401 0.608,-0.433 0.599,-0.462C0.589,-0.491 0.576,-0.515 0.558,-0.535C0.541,-0.555 0.519,-0.57 0.494,-0.581C0.469,-0.592 0.44,-0.597 0.408,-0.597C0.375,-0.597 0.346,-0.592 0.32,-0.581C0.295,-0.57 0.273,-0.555 0.256,-0.535C0.238,-0.515 0.225,-0.491 0.216,-0.462C0.206,-0.433 0.202,-0.401 0.202,-0.365C0.202,-0.328 0.206,-0.296 0.216,-0.267C0.225,-0.238 0.238,-0.214 0.256,-0.194C0.273,-0.173 0.295,-0.158 0.32,-0.148C0.346,-0.137 0.375,-0.132 0.408,-0.132C0.44,-0.132 0.469,-0.137 0.494,-0.148C0.519,-0.158 0.541,-0.173 0.558,-0.194C0.576,-0.214 0.589,-0.238 0.599,-0.267C0.608,-0.296 0.613,-0.328 0.613,-0.365Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,29.3823,0)">
<path d="M0.328,-0.371C0.372,-0.371 0.403,-0.382 0.423,-0.403C0.442,-0.424 0.452,-0.453 0.452,-0.491C0.452,-0.507 0.449,-0.522 0.444,-0.536C0.439,-0.55 0.431,-0.561 0.421,-0.571C0.411,-0.581 0.398,-0.589 0.383,-0.594C0.367,-0.599 0.349,-0.602 0.328,-0.602L0.24,-0.602L0.24,-0.371L0.328,-0.371ZM0.328,-0.729C0.379,-0.729 0.423,-0.722 0.46,-0.71C0.497,-0.698 0.527,-0.681 0.551,-0.66C0.575,-0.639 0.592,-0.614 0.604,-0.585C0.615,-0.556 0.621,-0.524 0.621,-0.491C0.621,-0.454 0.615,-0.421 0.603,-0.391C0.591,-0.36 0.574,-0.334 0.55,-0.313C0.526,-0.291 0.495,-0.274 0.458,-0.262C0.421,-0.25 0.378,-0.243 0.328,-0.244L0.24,-0.244L0.24,-0L0.071,-0L0.071,-0.729L0.328,-0.729Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,40.8538,0)">
<path d="M0.241,-0.599L0.241,-0.429L0.47,-0.429L0.47,-0.304L0.241,-0.304L0.241,-0.13L0.54,-0.13L0.54,-0L0.071,-0L0.071,-0.729L0.54,-0.729L0.54,-0.599L0.241,-0.599Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,51.189,0)">
<path d="M0.308,-0.386C0.331,-0.386 0.35,-0.389 0.366,-0.395C0.382,-0.401 0.396,-0.409 0.406,-0.419C0.416,-0.429 0.424,-0.441 0.429,-0.455C0.433,-0.469 0.436,-0.484 0.436,-0.5C0.436,-0.532 0.425,-0.557 0.404,-0.575C0.383,-0.593 0.351,-0.602 0.308,-0.602L0.24,-0.602L0.24,-0.386L0.308,-0.386ZM0.667,-0L0.514,-0C0.485,-0 0.465,-0.011 0.453,-0.032L0.332,-0.244C0.326,-0.253 0.32,-0.259 0.313,-0.263C0.306,-0.267 0.296,-0.27 0.283,-0.27L0.24,-0.27L0.24,-0L0.071,-0L0.071,-0.729L0.308,-0.729C0.36,-0.729 0.405,-0.723 0.442,-0.712C0.479,-0.701 0.51,-0.686 0.533,-0.667C0.557,-0.648 0.574,-0.625 0.585,-0.599C0.595,-0.572 0.601,-0.544 0.601,-0.513C0.601,-0.489 0.597,-0.467 0.591,-0.446C0.585,-0.425 0.575,-0.405 0.563,-0.387C0.551,-0.369 0.535,-0.354 0.517,-0.34C0.499,-0.326 0.478,-0.314 0.455,-0.305C0.466,-0.299 0.476,-0.292 0.486,-0.284C0.495,-0.275 0.504,-0.265 0.512,-0.254L0.667,-0Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,63.0483,0)">
<path d="M0.456,-0.279L0.388,-0.478C0.383,-0.491 0.378,-0.506 0.372,-0.523C0.366,-0.54 0.361,-0.559 0.355,-0.579C0.35,-0.558 0.345,-0.539 0.339,-0.522C0.333,-0.505 0.328,-0.49 0.323,-0.477L0.256,-0.279L0.456,-0.279ZM0.724,-0L0.593,-0C0.578,-0 0.567,-0.003 0.558,-0.01C0.549,-0.017 0.542,-0.026 0.537,-0.037L0.494,-0.164L0.217,-0.164L0.174,-0.037C0.17,-0.027 0.164,-0.019 0.154,-0.011C0.145,-0.004 0.133,-0 0.119,-0L-0.013,-0L0.269,-0.729L0.442,-0.729L0.724,-0Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,74.592,0)">
<path d="M0.594,-0.595L0.389,-0.595L0.389,-0L0.22,-0L0.22,-0.595L0.015,-0.595L0.015,-0.729L0.594,-0.729L0.594,-0.595Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,85.5765,0)">
<rect x="0.071" y="-0.729" width="0.17" height="0.729" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,91.1861,0)">
<path d="M0.724,-0.729L0.432,-0L0.279,-0L-0.013,-0.729L0.123,-0.729C0.138,-0.729 0.15,-0.725 0.159,-0.718C0.168,-0.711 0.174,-0.703 0.179,-0.692L0.32,-0.302C0.327,-0.285 0.333,-0.266 0.34,-0.246C0.346,-0.226 0.352,-0.205 0.358,-0.183C0.362,-0.205 0.367,-0.226 0.373,-0.246C0.379,-0.266 0.385,-0.285 0.392,-0.302L0.532,-0.692C0.536,-0.701 0.542,-0.71 0.552,-0.717C0.561,-0.725 0.573,-0.729 0.587,-0.729L0.724,-0.729Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,104.01,0)">
<path d="M0.241,-0.599L0.241,-0.429L0.47,-0.429L0.47,-0.304L0.241,-0.304L0.241,-0.13L0.54,-0.13L0.54,-0L0.071,-0L0.071,-0.729L0.54,-0.729L0.54,-0.599L0.241,-0.599Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(18.037,0,0,18.037,-13.068,0)">
<path d="M0.24,-0.434L0.267,-0.434C0.292,-0.434 0.31,-0.441 0.321,-0.457L0.485,-0.695C0.494,-0.708 0.505,-0.716 0.516,-0.721C0.527,-0.726 0.541,-0.729 0.558,-0.729L0.705,-0.729L0.489,-0.434C0.473,-0.414 0.457,-0.399 0.439,-0.39C0.452,-0.385 0.463,-0.379 0.474,-0.371C0.484,-0.362 0.494,-0.351 0.503,-0.338L0.723,-0L0.572,-0C0.562,-0 0.554,-0.001 0.547,-0.002C0.54,-0.003 0.534,-0.005 0.529,-0.008C0.524,-0.011 0.52,-0.014 0.516,-0.018C0.512,-0.022 0.509,-0.026 0.506,-0.031L0.341,-0.285C0.335,-0.294 0.327,-0.3 0.318,-0.304C0.309,-0.308 0.296,-0.31 0.281,-0.31L0.24,-0.31L0.24,-0L0.071,-0L0.071,-0.729L0.24,-0.729L0.24,-0.434Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
<g id="WTF" transform="matrix(4.16667,0,0,4.16667,-363.557,-181.762)">
<g transform="matrix(63.848,0,0,63.848,353.279,347.753)">
<path d="M0.59,-0.605L0.378,-0.605L0.378,-0L0.227,-0L0.227,-0.605L0.015,-0.605L0.015,-0.726L0.59,-0.726L0.59,-0.605Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(63.848,0,0,63.848,391.843,347.753)">
<path d="M0.227,-0.608L0.227,-0.408L0.488,-0.408L0.488,-0.29L0.227,-0.29L0.227,-0L0.076,-0L0.076,-0.726L0.538,-0.726L0.538,-0.608L0.227,-0.608Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
<g transform="matrix(63.848,0,0,63.848,282.658,347.753)">
<path d="M1.052,-0.726L0.827,-0L0.692,-0L0.543,-0.475C0.541,-0.481 0.538,-0.489 0.536,-0.497C0.534,-0.505 0.532,-0.513 0.53,-0.522C0.528,-0.513 0.525,-0.505 0.523,-0.497C0.521,-0.489 0.518,-0.481 0.516,-0.475L0.366,-0L0.23,-0L0.006,-0.726L0.132,-0.726C0.145,-0.725 0.155,-0.723 0.164,-0.717C0.173,-0.711 0.179,-0.703 0.182,-0.693L0.294,-0.284C0.297,-0.272 0.299,-0.26 0.302,-0.247C0.305,-0.234 0.308,-0.22 0.311,-0.205C0.314,-0.22 0.317,-0.234 0.32,-0.247C0.323,-0.26 0.327,-0.272 0.331,-0.284L0.462,-0.693C0.465,-0.701 0.47,-0.708 0.479,-0.715C0.488,-0.722 0.499,-0.725 0.512,-0.726L0.556,-0.726C0.569,-0.725 0.579,-0.722 0.587,-0.716C0.595,-0.71 0.602,-0.702 0.606,-0.693L0.736,-0.284C0.74,-0.273 0.744,-0.261 0.747,-0.249C0.75,-0.236 0.753,-0.223 0.757,-0.209C0.759,-0.223 0.762,-0.236 0.764,-0.249C0.767,-0.261 0.769,-0.273 0.772,-0.284L0.885,-0.693C0.887,-0.701 0.893,-0.709 0.902,-0.716C0.911,-0.722 0.921,-0.725 0.934,-0.726L1.052,-0.726Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
</g>
<g id="Einhorn" transform="matrix(1,0,0,1,-31.2941,-563.989)">
<path d="M450.529,1662.06L400.757,1697.42L401.385,1712.12C401.385,1712.12 401.392,1712.51 401.318,1712.69C401.189,1713.12 400.944,1713.39 400.944,1713.39L450.529,1662.06Z" style="fill:#fff;"/>
<path d="M736.631,1698.47L756.815,1695.93C756.815,1695.93 757.296,1695.91 757.696,1695.65C758.083,1695.4 758.264,1695.06 758.264,1695.06L750.801,1710.64C750.801,1710.64 750.463,1711.42 749.582,1711.56C748.632,1711.72 748.087,1711.18 748.087,1711.18L743.517,1707.05L745.991,1710.95C745.991,1710.95 746.486,1711.78 746.06,1712.62C745.565,1713.62 744.582,1713.64 744.582,1713.64L734.515,1714.3C734.515,1714.3 735.304,1714.06 735.548,1713.76C735.8,1713.44 736.025,1712.42 736.025,1712.42L736.631,1698.47Z" style="fill:#fff;"/>
<g transform="matrix(-1,0,0,1,1133.78,-0.317371)">
<path d="M736.631,1698.47L756.815,1695.93C756.815,1695.93 757.296,1695.91 757.696,1695.65C758.083,1695.4 758.264,1695.06 758.264,1695.06L750.801,1710.64C750.801,1710.64 750.463,1711.42 749.582,1711.56C748.632,1711.72 748.087,1711.18 748.087,1711.18L743.517,1707.05L745.991,1710.95C745.991,1710.95 746.486,1711.78 746.06,1712.62C745.565,1713.62 744.582,1713.64 744.582,1713.64L734.515,1714.3C734.515,1714.3 735.304,1714.06 735.548,1713.76C735.8,1713.44 736.025,1712.42 736.025,1712.42L736.631,1698.47Z" style="fill:#fff;"/>
</g>
<path d="M392.458,1653.33L445.559,1660.94L398.452,1694.68L377.352,1692.04C377.352,1692.04 376.875,1691.98 376.441,1692.17C375.813,1692.44 375.559,1692.97 375.559,1692.97L392.458,1653.33Z" style="fill:#fff;"/>
<g transform="matrix(-1,0,0,1,1133.82,0.344083)">
<path d="M392.458,1653.33L445.559,1660.94L398.452,1694.68L377.352,1692.04C377.352,1692.04 376.875,1691.98 376.441,1692.17C375.813,1692.44 375.559,1692.97 375.559,1692.97L392.458,1653.33Z" style="fill:#fff;"/>
</g>
<path d="M671.12,1573.37L702.593,1592.58L707.544,1588.92L698.064,1578.83L687.348,1576.59L689.224,1568.43C689.224,1568.43 689.271,1568.29 689.281,1568.09C689.288,1567.93 689.255,1567.77 689.255,1567.77L686.724,1550.74C686.724,1550.74 686.529,1549.58 685.362,1549.35C684.059,1549.08 683.457,1550.14 683.457,1550.14L674.166,1565.5C674.166,1565.5 674.065,1565.68 674.02,1565.84C673.954,1566.06 673.947,1566.24 673.947,1566.24L673.835,1574.13L671.12,1573.37Z" style="fill:#fff;"/>
<g transform="matrix(-1,0,0,1,1133.81,-0.623595)">
<path d="M670.409,1573.25L702.616,1592.94L707.454,1589.14L698.064,1578.83L687.348,1576.59L689.224,1568.43C689.224,1568.43 689.271,1568.29 689.281,1568.09C689.288,1567.93 689.255,1567.77 689.255,1567.77L686.724,1550.74C686.724,1550.74 686.529,1549.58 685.362,1549.35C684.059,1549.08 683.457,1550.14 683.457,1550.14L674.166,1565.5C674.166,1565.5 674.065,1565.68 674.02,1565.84C673.954,1566.06 673.947,1566.24 673.947,1566.24L673.84,1573.91L670.409,1573.25Z" style="fill:#fff;"/>
</g>
<path d="M427.91,1594.32L407.278,1606.88L315.202,1511.83C315.202,1511.83 314.118,1510.66 315.278,1509.41C316.302,1508.31 317.631,1509.24 317.631,1509.24L427.91,1594.32Z" style="fill:#fff;"/>
<g transform="matrix(-1,0,0,1,1133.84,0.346916)">
<path d="M427.91,1594.32L407.278,1606.88L315.202,1511.83C315.202,1511.83 314.118,1510.66 315.278,1509.41C316.302,1508.31 317.631,1509.24 317.631,1509.24L427.91,1594.32Z" style="fill:#fff;"/>
</g>
<path d="M352.629,1973.55L412.821,1957.45L564.149,1813.8L502.768,1776.15L352.629,1973.55Z" style="fill:#fff;"/>
<path d="M724.493,1958.33L791.81,1974.99L636.355,1779.22L570.066,1813.9L724.493,1958.33Z" style="fill:#fff;"/>
<path d="M567.109,1811.42L634.096,1776.37L566.931,1691.79L504.928,1773.31L567.109,1811.42Z" style="fill:#fff;"/>
<path d="M501.388,1771.76L565.007,1688.47L507.888,1603.52L471.991,1672.38L501.388,1771.76Z" style="fill:#fff;"/>
<path d="M568.964,1688.62L636.117,1772.79L662.194,1673.36L625.972,1603.85L568.964,1688.62Z" style="fill:#fff;"/>
<path d="M628.44,1600.9L663.644,1574.69L681.595,1659.26L664.468,1669.99L628.44,1600.9Z" style="fill:#fff;"/>
<path d="M452.254,1658.94L469.378,1669.67L505.406,1600.56L470.221,1574.36L452.254,1658.94Z" style="fill:#fff;"/>
<path d="M409.728,1609.57L466.44,1574.95L449.265,1655.87L409.728,1609.57ZM419.698,1608.4C418.738,1609.21 418.917,1610.78 420.06,1611.35L425.353,1613.99C426.003,1614.31 426.771,1614.21 427.32,1613.75L432.618,1609.17C433.604,1608.31 433.359,1606.71 432.159,1606.19C425.3,1602.76 425.728,1603.15 420.361,1607.83C420.143,1608.01 419.68,1608.37 419.698,1608.4Z" style="fill:#fff;"/>
<g transform="matrix(-1,0,0,1,1133.87,0.365109)">
<path d="M450.529,1662.06L400.757,1697.42L401.402,1712.11C401.402,1712.11 401.412,1712.43 401.327,1712.69C401.198,1713.08 400.954,1713.36 400.954,1713.36L450.529,1662.06Z" style="fill:#fff;"/>
</g>
<path d="M667.407,1575.3L724.122,1609.91L684.599,1656.21L667.407,1575.3ZM707.873,1603.98C707.655,1603.99 707.437,1604.03 707.227,1604.13L701.695,1606.53C700.477,1607.05 700.242,1608.66 701.232,1609.52L706.538,1614.1C707.075,1614.57 707.86,1614.67 708.506,1614.34L713.79,1611.69C714.933,1611.11 715.121,1609.57 714.156,1608.74L709.095,1604.41C708.754,1604.12 708.323,1603.97 707.873,1603.98Z" style="fill:#fff;"/>
<path d="M687.949,1657.75L740.377,1650.89C740.377,1650.89 731.48,1619.35 729.222,1611.36C729.041,1610.72 728.918,1610.57 728.71,1610.53C728.604,1610.5 728.323,1610.47 727.692,1611.21C721.177,1618.84 687.949,1657.75 687.949,1657.75Z" style="fill:#fff;"/>
<g transform="matrix(-1,0,0,1,1133.99,0.137922)">
<path d="M688.136,1657.23L740.413,1650.04C740.413,1650.04 731.949,1620.01 729.672,1611.95C729.314,1610.68 728.761,1610.52 728.548,1610.52C728.308,1610.52 728.093,1610.44 727.596,1611.02C721.135,1618.59 688.136,1657.23 688.136,1657.23Z" style="fill:#fff;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1 +1,18 @@
/*
* SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
$gray-100: #edefeb;
$gray-800: #344b5d;
$primary: #0790a9;
$dark: $gray-800;
$body-bg: $gray-100;
$link-decoration: none;
$link-hover-decoration: underline;
$spinner-animation-speed: 1s;

View File

@ -1,4 +1,9 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div>
<label for="searchText" class="form-label fw-bold">{{ label }}</label>
@ -11,61 +16,20 @@
id="searchText"
v-model="searchText"
@keyup="search()"
@keyup.enter="addResult()"
/>
</div>
<div class="col">
<div v-if="selectedResult">
<div v-if="type === 'contacttype'">
<input
type="text"
class="form-control"
id="contactContent"
v-model="contactContent"
/>
</div>
<div v-if="type === 'language'">
<select
class="form-select"
aria-label="Selektiere dein Level"
v-model="level"
>
<option v-for="(value, key) in languagesSelection" :value="key" :key="key">{{value}}</option>
</select>
</div>
<div v-else>
<select
class="form-select"
aria-label="Selektiere dein Level"
v-model="level"
>
<option v-for="(value, key) in levelSelection" :value="key" :key="key">{{value}}</option>
</select>
</div>
</div>
</div>
<div class="col">
<button
v-if="selectedResult && !selectedResult.edit"
v-if="searchText != ''"
type="button"
class="btn btn-outline-success"
aria-label="Hinzufügen"
@click="addSelectedResult()"
@click="addResult()"
>
<img
src="/img/bootstrap-icons-1.5.0/plus-lg.svg"
alt="Hinzufügen Icon"
/>
<i clas="bi-plus-lg"></i>
Hinzufügen
</button>
<button
v-if="selectedResult && selectedResult.edit"
type="button"
class="btn btn-outline-success"
aria-label="Hinzufügen"
@click="editSelectedResult()"
>
Änderung speichern
</button>
</div>
</div>
<div class="" v-if="searchResults">
@ -74,13 +38,7 @@
class="list-group-item"
v-for="result in searchResults"
:key="result.id"
:class="{
'bg-info':
selectedResult &&
selectedResult.id &&
result.id === selectedResult.id,
}"
@click="selectedResult = result"
@click="addResult(result)"
>
{{ result.name }}
</li>
@ -90,19 +48,21 @@
:values="values"
:type="type"
:editable="true"
@edit-value="editValue($event)"
@remove-value="removeValue($event)"
></profile-list>
@update-values="this.$emit('update-values', this.values)"
>
</profile-list>
</div>
</template>
<script>
import ProfileList from "@/components/ProfileList";
import { mapState } from 'vuex'
import levelJson from "@/assets/skill_level.json"
import languagesJson from "@/assets/language_level.json"
import RequestMixin from "@/mixins/request.mixin"
import ProfileList from "@/components/ProfileList";
export default {
name: "AutoComplete",
mixins: [RequestMixin],
components: {
ProfileList,
},
@ -121,77 +81,40 @@ export default {
return {
iconUrl: this.apiUrl,
searchText: "",
contactContent: "",
searchResults: [],
showErrorMessage: false,
level: "1",
selectedResult: null,
levelSelection: levelJson,
languagesSelection: languagesJson,
};
},
computed: {
...mapState(['currentUserId'])
},
methods: {
async search() {
try {
const request = await this.axios.get(
`${this.apiUrl}/${this.type}s?search=${this.searchText}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
if (request.status === 200) {
this.searchResults = request.data[`${this.type}s`];
}
} catch (error) {
console.error();
this.showErrorMessage = true;
}
},
addSelectedResult() {
addResult(result = false) {
if (!result) result = this.searchResults[0];
if (
this.values
.map((item) => item[this.type].id)
.includes(this.selectedResult.id)
this.values.map((item) => item[this.type].name).includes(result.name)
) {
return false;
}
let changeValues = Object.assign(this.values);
let newValue = {
profile_id: localStorage.getItem("user_id"),
profile_id: this.currentUserId,
};
if (this.type != "contacttype") {
newValue.level = this.level;
newValue.level = 1;
} else {
newValue.content = this.contactContent;
newValue.content = "";
}
newValue[this.type] = this.selectedResult;
changeValues.push(newValue);
newValue[this.type] = result;
changeValues.unshift(newValue);
this.searchText = "";
this.searchResults = [];
this.selectedResult = null;
this.level = 1;
this.$emit("update-values", changeValues);
},
editSelectedResult() {
this.values.map((item) => {
if (item[this.type].name == this.selectedResult.name) {
if (this.type != "contacttype") {
item.level = this.level;
} else {
item.content = this.contactContent;
}
}
return item;
});
this.$emit("update-values", this.values);
},
removeValue(valueId) {
removeValue(valueName) {
const newValues = this.values.filter((value) => {
if (valueId === value[this.type].id) {
if (valueName === value[this.type].name) {
return false;
} else {
return true;
@ -199,21 +122,6 @@ export default {
});
this.$emit("update-values", newValues);
},
editValue(value) {
this.searchResults = [value[this.type]];
this.selectedResult = {
...value[this.type],
level: value.level,
edit: true,
};
if (this.type != "contacttype") {
this.level = value.level;
} else {
this.contactContent = value.content;
}
this.level = value.level;
},
},
};
</script>

37
src/components/Avatar.vue Normal file
View File

@ -0,0 +1,37 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="avatar bg-dark">
{{ avatarLetters }}
</div>
</template>
<script>
export default {
props: {
name: String
},
computed: {
avatarLetters() {
return this.name.substr(0, 2)
}
}
}
</script>
<style scoped>
.avatar {
align-items: center;
border-radius: .25rem;
color: white;
display: flex;
font-weight: bold;
height: 2.5rem;
justify-content: center;
width: 2.5rem;
}
</style>

47
src/components/Footer.vue Normal file
View File

@ -0,0 +1,47 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<footer class="bg-dark py-5">
<div class="container">
<div class="row text-center text-sm-start">
<div class="col-sm-6 d-sm-flex justify-content-center mb-3 mb-sm-0">
<div class="d-inline-block">
<div class="fw-bold text-white mb-2">Kompetenzinventar</div>
<ul class="list-unstyled">
<li><a href="https://git.wtf-eg.de/kompetenzinventar">Quellcode</a></li>
<li><a href="https://git.wtf-eg.de/kompetenzinventar/ki-frontend/issues/new">Problem melden</a></li>
</ul>
</div>
</div>
<div class="col-sm-6 d-sm-flex justify-content-center">
<div class="d-inline-block">
<ul class="list-unstyled">
<li><a href="https://wtf-eg.de/impressum/">Impressum</a></li>
<li><a href="https://wtf-eg.de/datenschutz/">Datenschutzerklärung</a></li>
</ul>
<img class="wtf-logo wtf-logo--footer" src="@/assets/img/wtf_logo_white.svg">
</div>
</div>
</div>
</div>
</footer>
</template>
<style scoped>
a {
color: #fff;
text-decoration: none;
}
a:hover {
color: #fff;
text-decoration: underline;
}
.wtf-logo--footer {
max-width: 200px;
}
</style>

110
src/components/Navbar.vue Normal file
View File

@ -0,0 +1,110 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<nav class="navbar navbar-expand-lg navbar-light bg-white">
<div class="container-fluid">
<router-link
class="navbar-brand"
:to="{ path:'/s/search' }"
>
<img class="wtf-logo wtf-logo--navbar" src="@/assets/img/wtf_logo.svg">
<span class="d-none d-sm-inline">Kompetenzinventar</span>
<span class="d-sm-none">KI</span>
</router-link>
<button
@click="toggleMobileNav"
class="navbar-toggler"
type="button"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div
class="collapse navbar-collapse d-lg-flex"
:class="{ show: showMobileNav }"
id="navbarSupportedContent"
>
<ul class="navbar-nav mb-2 mb-lg-0 me-auto">
<li class="nav-item">
<router-link
class="nav-link"
:to="{ path: `/s/search` }"
active-class="active"
>Suche</router-link
>
</li>
<li class="nav-item">
<router-link
class="nav-link"
:to="{ path: `/s/profile/${currentUserId}` }"
active-class="active"
>Mein Profil</router-link
>
</li>
<li class="nav-item">
<router-link
class="nav-link"
:to="{ path: `/s/profile-edit` }"
active-class="active"
>Bearbeiten</router-link
>
</li>
</ul>
<ul class="navbar-nav">
<li class="nav-item">
<button class="btn btn-danger w-100" @click="logout()">
<i class="bi bi-box-arrow-right"></i>
Logout
</button>
</li>
</ul>
</div>
</div>
</nav>
</template>
<script>
import { mapState } from 'vuex'
import RequestMixin from '@/mixins/request.mixin'
export default {
name: 'Navbar',
mixins: [RequestMixin],
data() {
return {
showMobileNav: false
}
},
computed: {
...mapState(['currentUserId'])
},
methods: {
toggleMobileNav() {
this.showMobileNav = !this.showMobileNav
},
logout() {
this.$store.dispatch('clear')
this.$router.push({ path: '/' });
},
}
}
</script>
<style>
.wtf-logo--navbar {
height: 40px;
margin-bottom: -5px;
margin-top: -5px;
}
</style>

View File

@ -1,54 +1,97 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<ul>
<li v-for="value in values" :key="value.id">
<img
style="max-width: 64px"
v-if="value[type].icon_url"
:src="iconUrl + value[type].icon_url"
:alt="`${value[type].name} Logo`"
/>
{{ value[type].name }}
<span v-if="value.level">
<span v-if="type == 'skill'">({{ levelSelection[value.level] }})</span>
<span v-if="type == 'language'">({{ languagesSelection[value.level] }})</span>
</span>
<span v-if="value.content">:
<span v-if="value[type].name === 'E-Mail'">
<a :href="`mailto:${value.content}`">{{ value.content }}</a>
</span>
<span v-else>
{{ value.content }}
</span>
</span>
<button
v-if="this.editable"
type="button"
class="btn btn-outline-warning m-2"
aria-label="Bearbeiten"
@click="this.$emit('editValue', value)"
>
<img
src="/img/bootstrap-icons-1.5.0/pencil.svg"
alt="Bearbeiten Icon"
/>
</button>
<button
v-if="this.editable"
type="button"
class="btn btn-outline-danger m-2"
aria-label="Löschen"
@click="this.$emit('removeValue', value[type].id)"
>
<img src="/img/bootstrap-icons-1.5.0/trash.svg" alt="Löschen Icon" />
</button>
<li v-for="(value, valueKey) in values" :key="value.id">
<div class="row m-1">
<div class="col">
<img
style="max-width: 64px"
v-if="value[type].icon_url"
:src="iconUrl + value[type].icon_url"
:alt="`${value[type].name} Logo`"
/>
{{ value[type].name }}
</div>
<div class="col">
<div v-if="type == 'skill'">
<div v-if="editable">
<select
v-if="editableValues[valueKey]"
class="form-select"
aria-label="Selektiere dein Level"
v-model="editableValues[valueKey].level"
@input="$emit('update-values', editableValues)"
>
<option
v-for="(value, key) in levelSelection"
:value="key"
:key="key"
>
{{ value }}
</option>
</select>
</div>
<div v-else><span v-if="value.level">({{ levelSelection[value.level] }})</span></div>
</div>
<div v-else-if="type == 'language'">
<div v-if="editable">
<div v-if="editable">
<select
v-if="editableValues[valueKey]"
class="form-select"
aria-label="Selektiere dein Level"
v-model="editableValues[valueKey].level"
@input="$emit('update-values', editableValues)"
>
<option
v-for="(value, key) in languagesSelection"
:value="key"
:key="key"
>
{{ value }}
</option>
</select>
</div>
</div>
<div v-else><span v-if="value.level">({{languagesSelection[value.level]}})</span></div>
</div>
<div v-else-if="type == 'contacttype'">
<div v-if="editable">
<input class="form-control" v-model="editableValues[valueKey].content"/>
</div>
<div v-else>
<span v-if="value[type].name === 'E-Mail'">
<a :href="`mailto:${value.content}`">{{ value.content }}</a>
</span>
<span v-else>
{{ value.content }}
</span>
</div>
</div>
</div>
<div class="col">
<button
v-if="editable"
type="button"
class="btn btn-outline-danger"
aria-label="Löschen"
@click="$emit('removeValue', value[type].name)"
>
<i class="bi-trash"></i>
</button>
</div>
</div>
</li>
</ul>
</template>
<script>
import levelJson from "@/assets/skill_level.json"
import languagesJson from "@/assets/language_level.json"
import levelJson from "@/assets/skill_level.json";
import languagesJson from "@/assets/language_level.json";
export default {
name: "ProfileList",
@ -58,6 +101,7 @@ export default {
},
values: {
type: Array,
required: true,
},
editable: {
type: Boolean,
@ -69,7 +113,13 @@ export default {
iconUrl: this.apiUrl,
levelSelection: levelJson,
languagesSelection: languagesJson,
}
}
editableValues: this.values,
};
},
watch: {
values: function (newVal) {
this.editableValues = newVal;
},
},
};
</script>

View File

@ -0,0 +1,54 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<router-link
class="text-decoration-none d-flex"
:to="{ path: `/s/profile/${profile.user_id}` }"
>
<div class="card w-100">
<div class="card-body d-flex">
<div class="d-flex align-items-center justify-content-center me-3">
<Avatar :name="profile.nickname"/>
</div>
<div class="text-body">
<h5 class="card-title mb-1 lh-1">
{{ profile.nickname}}
<span v-if="profile.pronouns"> ({{ profile.pronouns }})</span>
</h5>
<small
class="card-text lh-1 text-dark"
v-if="profile.skills && profile.skills.length > 0"
>
Top-Fähigkeiten: {{ topSkills }}
</small>
</div>
</div>
</div>
</router-link>
</template>
<script>
import Avatar from '@/components/Avatar'
export default {
components: {
Avatar,
},
props: {
profile: Object
},
computed: {
topSkills() {
return this.profile.skills.slice(0, 5).map(s => s.skill.name).join(', ')
}
}
}
</script>
<style scoped>
.card:hover {
background-color: #f8f9fa;
}
</style>

View File

@ -0,0 +1,9 @@
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="spinner-grow" role="status"></div>
</template>

View File

@ -1,17 +1,20 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import { createApp } from 'vue/dist/vue.esm-bundler'
import App from './App.vue'
import router from './router'
import store from '@/store'
import axios from 'axios'
import 'bootstrap-icons/font/bootstrap-icons.css'
import './assets/global.scss'
const app = createApp(App)
app.use(router)
app.use(store)
app.config.globalProperties.axios=axios
app.config.globalProperties.apiUrl = window.ki.apiUrl
app.mount('#app')

170
src/mixins/request.mixin.js Normal file
View File

@ -0,0 +1,170 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import store from '@/store'
export default {
methods: {
async submitLogin() {
this.showErrorMessage = false;
try {
const data = JSON.stringify({
username: this.username,
password: this.password,
})
const response = await fetch(`${this.apiUrl}/users/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: data
})
if (!response.ok) {
this.showErrorMessage = true
return
}
const responseData = await response.json()
store.commit('setCurrentUserId', parseInt(responseData.user_id, 10))
store.commit('setToken', responseData.token)
this.$router.push({ path: '/s/search' });
} catch (error) {
console.error(error);
this.showErrorMessage = true;
}
},
async search() {
try {
const response = await fetch(`${this.apiUrl}/${this.type}s?search=${this.searchText}`, {
headers: {
Authorization: `Bearer ${store.state.token}`,
},
}
);
if (!response.ok) {
console.error();
this.showErrorMessage = true;
return
}
const responseData = await response.json()
this.searchResults = responseData[`${this.type}s`];
if (
!this.values
.map((item) => item[this.type].name.toLowerCase())
.includes(this.searchText.toLowerCase())
) {
this.searchResults.unshift({ name: this.searchText });
}
} catch (error) {
console.error();
this.showErrorMessage = true;
}
},
async initEditPage() {
const userId = store.state.currentUserId
const url = `${this.apiUrl}/users/${userId}/profile`
try {
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${store.state.token}`
},
}
);
if (!response.ok) {
return
}
const responseData = await response.json()
this.profile = responseData.profile;
} catch (error) {
console.error(error);
}
},
async submitFormEdit() {
this.showErrorMessage = false
this.showSuccessMessage = false
const userId = store.state.currentUserId
try {
const body = JSON.stringify(this.profile)
const response = await fetch(
`${this.apiUrl}/users/${userId}/profile`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${store.state.token}`,
'Content-Type': 'application/json',
},
body
}
);
if (!response.ok) {
this.showErrorMessage = true
return
}
this.showSuccessMessage = true
} catch (error) {
console.error(error);
this.showErrorMessage = true;
}
},
async initViewPage() {
try {
const response = await fetch(`${this.apiUrl}/users/${this.$route.params.memberId}/profile`, {
headers: { Authorization: `Bearer ${store.state.token}` },
}
);
if (!response.ok) {
return
}
const responseData = await response.json()
store.commit('setCurrentProfile', responseData.profile)
} catch (error) {
console.error(error);
}
},
async submitSearch() {
this.showErrorMessage = false;
try {
const url = new URL(`${this.apiUrl}/users/profiles`)
if (this.searchText != "") {
url.searchParams.append('nickname', this.searchText)
}
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${store.state.token}`,
},
});
if (!response.ok) {
this.showErrorMessage = true
return
}
const responseData = await response.json()
this.searchResults = responseData.profiles;
this.searchTotal = responseData.total;
} catch (error) {
console.error(error);
this.showErrorMessage = true;
}
},
},
}

View File

@ -1,5 +1,11 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import { createRouter, createWebHistory } from 'vue-router'
import store from '@/store'
import Index from '@/views/Index.vue'
import Search from '@/views/Search.vue'
import Edit from '@/views/profile/Edit.vue'
@ -13,9 +19,9 @@ const routes = [
template: "<router-view/>",
},
beforeEnter: (to, from, next) => {
if(localStorage.getItem('token') !== null){
if (store.state.token){
next()
}else{
} else {
next({path: '/', query: {url: to.fullPath, access: false}})
}
},

55
src/store/index.js Normal file
View File

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import { createStore } from 'vuex'
import search from './search'
const localStorageKeys = {
currentUserId: 'ki_current_user_id',
token: 'ki_token',
}
export default createStore({
modules: {
search,
},
state() {
return {
currentUserId: JSON.parse(localStorage.getItem(localStorageKeys.currentUserId)),
token: JSON.parse(localStorage.getItem(localStorageKeys.token)),
currentProfile: null
}
},
mutations: {
clearCurrentUserId(state) {
state.currentUserId = null
localStorage.removeItem(localStorageKeys.currentUserId)
},
setCurrentUserId(state, currentUserId) {
state.currentUserId = currentUserId
localStorage.setItem(
localStorageKeys.currentUserId,
JSON.stringify(currentUserId)
)
},
clearToken(state) {
state.token = null
localStorage.removeItem(localStorageKeys.token)
},
setToken(state, token) {
state.token = token
localStorage.setItem(localStorageKeys.token, JSON.stringify(token))
},
setCurrentProfile(state, profile) {
state.currentProfile = profile
}
},
actions: {
clear(context) {
context.commit('clearCurrentUserId')
context.commit('clearToken')
}
}
})

100
src/store/search.js Normal file
View File

@ -0,0 +1,100 @@
// SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
export default {
namespaced: true,
state() {
return {
searching: false,
showSpinner: false,
searched: false,
profiles: [],
error: false,
errorMessage: '',
query: {
search: ''
}
}
},
mutations: {
setSearching(state, searching) {
state.searching = searching
},
showSpinner(state) {
state.showSpinner = true
},
hideSpinner(state) {
state.showSpinner = false
},
clearProfiles(state) {
state.profiles = []
},
setProfiles(state, profiles) {
state.profiles = profiles
},
setError(state, error) {
state.error = error
},
setErrorMessage(state, errorMessage) {
state.errorMessage = errorMessage
},
setQuerySearch(state, search) {
state.query.search = search
}
},
actions: {
async search({state, commit, rootState}) {
if (state.searching) {
return
}
commit('setSearching', true)
const timeoutId = setTimeout(() => {
commit('showSpinner')
commit('clearProfiles')
}, 100)
commit('setError', false)
commit('setErrorMessage', '')
const url = new URL(`${window.ki.apiUrl}/users/profiles`)
if (state.query.search) {
url.searchParams.append('search', state.query.search)
}
const headers = {
Authorization: `Bearer ${rootState.token}`,
}
let response
try {
response = await fetch(url, {headers})
} catch {
commit('setError', true)
commit('clearProfiles')
commit('setSearching', false)
commit('hideSpinner')
return
}
clearTimeout(timeoutId)
if (!response.ok) {
commit('setError', true)
commit('clearProfiles')
commit('setSearching', false)
commit('hideSpinner')
return
}
const responseData = await response.json()
commit('setProfiles', responseData.profiles)
commit('setSearching', false)
commit('hideSpinner')
}
}
}

View File

@ -1,52 +1,61 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="container">
<h1>WTF Kompetenzinventar</h1>
<form @submit.prevent="submitLogin()">
<div class="mb-3">
<label for="exampleInputusername1" class="form-label"
>Benutzername:
</label>
<input
type="username"
class="form-control"
id="exampleInputusername1"
v-model="username"
required
/>
<div class="bg-wtf">
<div class="container pt-5">
<div class="text-center mb-5">
<img class="wtf-logo wtf-logo--index" src="@/assets/img/wtf_logo.svg">
<h1 class="text-white">Kompetenzinventar</h1>
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Passwort:</label>
<input
type="password"
class="form-control"
id="exampleInputPassword1"
v-model="password"
required
/>
</div>
<button type="submit" class="btn btn-primary mb-4">Login</button>
</form>
<a href="https://resetpw.wtf-eg.de/">Globales WTF Passwort zurücksetzen</a>
<div
class="alert alert-danger mb-4 mt-4"
role="alert"
v-if="showErrorMessage"
>
Mit deinen Login Daten ist ein Fehler aufgetreten. Versuch es nochmal oder
<a href="https://resetpw.wtf-eg.de/">hast du dein Passwort vergessen?</a>.
<form @submit.prevent="submitLogin()" class="card bg-white login-form">
<div class="card-body">
<div class="mb-3">
<label for="exampleInputusername1" class="form-label" >
WTF-Benutzername:
</label>
<input
type="username"
class="form-control"
id="exampleInputusername1"
v-model="username"
required
/>
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Passwort:</label>
<input
type="password"
class="form-control"
id="exampleInputPassword1"
v-model="password"
required
/>
</div>
<button type="submit" class="btn btn-primary">Login</button>
<a class="btn btn-link" href="https://resetpw.wtf-eg.de/">Passwort vergessen?</a>
<div
class="alert alert-danger mt-3 mb-0"
role="alert"
v-if="showErrorMessage"
>
Dein Benutzername oder Passwort ist falsch.<br>Versuche es noch einmal.
</div>
</div>
</form>
</div>
<p>
Das Login gilt nur für WTF eG Mitglieder. Du kannst dein LDAP Passwort
hier ändern.
</p>
</div>
</template>
<script>
import axios from "axios";
import RequestMixin from "@/mixins/request.mixin"
export default {
name: "Index",
mixins: [RequestMixin],
data() {
return {
showErrorMessage: false,
@ -54,35 +63,21 @@ export default {
password: "",
};
},
methods: {
async submitLogin() {
this.showErrorMessage = false;
try {
console.log(this.apiUrl)
const loginResult = await axios.post(
`${this.apiUrl}/users/login`,
{
username: this.username,
password: this.password,
}
);
console.log(loginResult);
console.log(loginResult.status);
if (loginResult.status === 200) {
console.log('if true')
this.showErrorMessage = false;
//success login
localStorage.setItem("token", loginResult.data.token);
localStorage.setItem("user_id", loginResult.data.user_id);
this.$router.push({ path: "/s/search" });
} else {
this.showErrorMessage = true;
}
} catch (error) {
console.error(error);
this.showErrorMessage = true;
}
},
},
};
</script>
<style scoped>
.container {
min-height: 100vh;
}
.login-form {
margin: 0 auto;
max-width: 500px;
}
.wtf-logo--index {
max-width: 200px;
}
</style>

View File

@ -1,102 +1,134 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="container">
<h1>Suche</h1>
<form @submit.prevent="submitSearch()">
<div class="row">
<div class="col">
<input
type="text"
class="form-control"
id="searchText"
v-model="searchText"
/>
</div>
<div class="col">
<button type="submit" class="btn btn-primary mb-4">
Suche starten
</button>
<div class="content">
<div class="bg-wtf text-white pt-3 pb-4">
<div class="container">
<div class="fs-3 text-center lh-1 mb-3">Finde WTF Member</div>
<div class="card mx-auto bg-white">
<div class="card-body">
<form @submit.prevent="handleSubmit">
<fieldset class="d-flex" :disabled="searching">
<div class="flex-grow-1 me-3">
<input
type="text"
class="form-control"
id="searchText"
v-model="searchText"
placeholder="Nick, Fähigkeit, Sprache"
ref="searchTextInput"
/>
</div>
<div class="">
<button type="submit" class="btn btn-primary">
<i class="bi-search"></i>
<span class="d-none d-md-inline"> Suchen</span>
</button>
</div>
</fieldset>
</form>
</div>
</div>
</div>
</form>
<div
class="alert alert-danger mb-4 mt-4"
role="alert"
v-if="showErrorMessage"
>
Bei der Suche ist ein Fehler aufgetreten
</div>
<div v-if="searchTotal == 0">
Es wurde kein Suchergebnis gefunden.
<p v-if="searchText !== ''">Probiere eine andere Suche.</p>
</div>
<div v-else>
<div class="row">
<div
class="col-4 p-2"
v-for="result in searchResults"
:key="result.user_id"
>
<router-link
class="text-decoration-none"
:to="{ path: `/s/profile/${result.user_id}` }"
>
<div class="card">
<div class="card-body">
<h5 class="card-title">
{{ result.nickname
}}<span v-if="result.pronouns"> ({{ result.pronouns }})</span>
</h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text" v-if="result.skills">
Fähigkeiten:
<span v-for="skill in result.skills" :key="skill.skill.name"
>{{ skill.skill.name }}
</span>
</p>
</div>
</div>
</router-link>
</div>
<div class="container pt-4 pb-3">
<div class="text-center" v-if="showSpinner">
<Spinner />
</div>
<div
class="fs-2 text-danger text-center"
role="alert"
v-if="error"
>
<div class="fs-1 mb-3">Kernel panic :/</div>
Bei der Suche ist ein Fehler aufgetreten.
</div>
<div v-else-if="showNoResults" class="fs-2 text-black-50 text-center">
<div class="fs-1 mb-3">nullptr :/</div>
Es wurde kein Suchergebnis gefunden.
<p v-if="searchText !== ''">Probiere eine andere Suche.</p>
</div>
<div v-else-if="showResults">
<SearchResult
v-for="profile in profiles"
:key="profile.user_id"
class="mb-3"
:profile="profile"
/>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import SearchResult from '@/components/SearchResult'
import Spinner from '@/components/Spinner'
export default {
name: "Search",
data() {
return {
showErrorMessage: false,
searchText: "",
searchResults: null,
searchTotal: 0,
};
name: 'Search',
components: {
SearchResult,
Spinner,
},
created() {
if (this.$route.query.query) this.searchText = this.$route.query.query;
this.submitSearch();
computed: {
...mapState({
searching: state => state.search.searching,
profiles: state => state.search.profiles,
error: state => state.search.error,
showSpinner: state => state.search.showSpinner,
}),
searchText: {
get() {
return this.$store.state.search.query.search
},
set(text) {
this.$store.commit('search/setQuerySearch', text)
}
},
showNoResults() {
return !this.searching && (!this.profiles || this.profiles.length === 0)
},
showResults() {
return !this.error && this.profiles && this.profiles.length > 0
}
},
watch: {
searching(value) {
if (value) {
if (this.$refs.searchTextInput) {
this.$refs.searchTextInput.focus()
}
}
}
},
methods: {
async submitSearch() {
this.showErrorMessage = false;
try {
let url = `${this.apiUrl}/users/profiles`;
if (this.searchText != "") {
url += `?nickname=${this.searchText}`;
}
const result = await this.axios.get(url, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
this.searchResults = result.data.profiles;
this.searchTotal = result.data.total;
} catch (error) {
console.error(error);
this.showErrorMessage = true;
}
},
handleSubmit() {
this.$router.push({ query: { query: this.searchText }})
this.$store.dispatch('search/search')
}
},
created() {
if (this.$route.query.query !== undefined) {
this.searchText = this.$route.query.query
this.$store.commit('search/clearProfiles')
}
this.$store.dispatch('search/search')
}
};
</script>
<style scoped>
.container {
max-width: 768px;
}
.content {
min-height: calc(100vh - 60px);
}
</style>

View File

@ -1,21 +1,38 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="container">
<h1>Profil bearbeiten</h1>
<form @submit.prevent="submitForm()">
<form @submit.prevent="submitFormEdit()">
<div class="row">
<div class="col">
<input type="radio" id="false" :value="false" v-model="profile.visible" class="mr-2"/>
<input
type="radio"
id="false"
:value="false"
v-model="profile.visible"
class="mr-2"
/>
<label for="false" class="m-2 fw-bold"> Nicht öffentlich</label>
</div>
<div class="col">
<input type="radio" id="true" :value="true" v-model="profile.visible" />
<input
type="radio"
id="true"
:value="true"
v-model="profile.visible"
/>
<label for="true" class="m-2 fw-bold"> Öffentlich</label>
</div>
</div>
<div id="visibilityHelp" class="form-text">
Erst wenn du dein Profil Öffentlich stellst, können andere Genoss:innen darauf zugreifen oder es in der Suche finden.
</div>
Erst wenn du dein Profil Öffentlich stellst, können andere Genoss:innen
darauf zugreifen oder es in der Suche finden.
</div>
<div class="row">
<div class="col-6 col-xs-12">
<label for="nickname" class="form-label fw-bold">Nickname:</label>
@ -82,16 +99,16 @@
></auto-complete>
<div class="col-12 col-xs-12">
<label for="availability" class="form-label fw-bold"
>Ich bin für Anfragen verfügbar:</label
>
<textarea
class="form-control"
id="availability"
rows="3"
v-model="profile.availability"
></textarea>
</div>
<label for="availability" class="form-label fw-bold"
>Ich bin für Anfragen verfügbar:</label
>
<textarea
class="form-control"
id="availability"
rows="3"
v-model="profile.availability"
></textarea>
</div>
<auto-complete
type="contacttype"
@ -130,7 +147,9 @@
</div>
</div>
<button type="submit" class="btn btn-outline-success mb-4 mt-4 col-12">Speichern</button>
<button type="submit" class="btn btn-outline-success mb-4 mt-4 col-12">
Speichern
</button>
<div
class="alert alert-danger mb-4 mt-4"
role="alert"
@ -149,11 +168,13 @@
</div>
</template>
<script>
import axios from "axios";
import RequestMixin from "@/mixins/request.mixin"
import AutoComplete from "@/components/AutoComplete";
export default {
name: "profileEdit",
mixins: [RequestMixin],
components: {
AutoComplete,
},
@ -181,46 +202,7 @@ export default {
};
},
async created() {
try {
const userProfile = await axios.get(
`${this.apiUrl}/users/${localStorage.getItem(
"user_id"
)}/profile`,
{
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
}
);
this.profile = userProfile.data.profile;
} catch (error) {
console.error(error);
}
},
methods: {
async submitForm() {
try {
const formSubmitResult = await axios.post(
`${this.apiUrl}/users/${localStorage.getItem(
"user_id"
)}/profile`,
this.profile,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
if (formSubmitResult.status === 200) {
// success
this.showSuccessMessage = true;
} else {
// failure
this.showErrorMessage = true;
}
} catch (error) {
console.error(error);
this.showErrorMessage = true;
}
}
await this.initEditPage();
},
};
</script>

View File

@ -1,4 +1,9 @@
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!--
SPDX-FileCopyrightText: WTF Kooperative eG <https://wtf-eg.de/>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div v-if="profile" class="container">
<h1>
@ -30,35 +35,30 @@
></profile-list>
<div v-if="profile.address">
<h3>Meine Location:</h3>
{{profile.address.city}} ({{profile.address.postcode}}), {{profile.address.country}}
{{profile.address.city}}<span v-if="profile.address && profile.address.postcode"> ({{profile.address.postcode}})</span>, {{profile.address.country}}
</div>
</div>
</template>
<script>
import ProfileList from "@/components/ProfileList";
import { mapState } from 'vuex'
import RequestMixin from '@/mixins/request.mixin'
import ProfileList from '@/components/ProfileList';
export default {
name: "profileView",
mixins: [RequestMixin],
components: {
ProfileList,
},
data() {
return {
profile: null
};
computed: {
...mapState({
profile: 'currentProfile'
})
},
async created() {
try {
const userProfile = await this.axios.get(
`${this.apiUrl}/users/${this.$route.params.memberId}/profile`,
{
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
}
);
this.profile = userProfile.data.profile;
} catch (error) {
console.error(error);
}
},
await this.initViewPage();
}
};
</script>