mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch 'master' into upgrade-styleguied
This commit is contained in:
commit
0f08ee34a4
@ -12,7 +12,7 @@ scripts/
|
||||
|
||||
cypress/
|
||||
|
||||
README.md
|
||||
README.md
|
||||
screenshot*.png
|
||||
lokalise.png
|
||||
.editorconfig
|
||||
.editorconfig
|
||||
|
||||
2
.env.template
Normal file
2
.env.template
Normal file
@ -0,0 +1,2 @@
|
||||
JWT_SECRET="b/&&7b78BF&fv/Vd"
|
||||
MAPBOX_TOKEN="pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ"
|
||||
@ -9,9 +9,11 @@ services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
- DOCKER_COMPOSE_VERSION=1.23.2
|
||||
- DOCKER_COMPOSE_VERSION=1.23.2 BACKEND_BRANCH=${TRAVIS_PULL_REQUEST_BRANCH:-${TRAVIS_BRANCH:-master}}
|
||||
|
||||
|
||||
before_install:
|
||||
- echo $BACKEND_BRANCH
|
||||
- sudo rm /usr/local/bin/docker-compose
|
||||
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
@ -21,7 +23,7 @@ install:
|
||||
- docker build --build-arg BUILD_COMMIT=$TRAVIS_COMMIT --target production -t humanconnection/nitro-web .
|
||||
- docker-compose -f docker-compose.yml -f docker-compose.travis.yml up -d
|
||||
- git clone https://github.com/Human-Connection/Nitro-Backend.git ../Nitro-Backend
|
||||
- git -C "../Nitro-Backend" checkout $TRAVIS_BRANCH || echo "Branch \`$TRAVIS_BRANCH\` does not exist, falling back to \`master\`"
|
||||
- git -C "../Nitro-Backend" checkout $BACKEND_BRANCH
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml -f ../Nitro-Backend/docker-compose.travis.yml up -d
|
||||
- yarn global add cypress wait-on
|
||||
- yarn add cypress-cucumber-preprocessor
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
FROM node:10-alpine as base
|
||||
LABEL Description="Web Frontend of the Social Network Human-Connection.org" Vendor="Human-Connection gGmbH" Version="0.0.1" Maintainer="Human-Connection gGmbH (developer@human-connection.org)"
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["yarn", "run", "start"]
|
||||
|
||||
# Expose the app port
|
||||
ARG BUILD_COMMIT
|
||||
ENV BUILD_COMMIT=$BUILD_COMMIT
|
||||
@ -14,6 +17,7 @@ RUN apk --no-cache add git
|
||||
COPY . .
|
||||
|
||||
FROM base as build-and-test
|
||||
RUN cp .env.template .env
|
||||
RUN yarn install --production=false --frozen-lockfile --non-interactive
|
||||
RUN cd styleguide && yarn install --production=false --frozen-lockfile --non-interactive \
|
||||
&& cd .. \
|
||||
@ -24,6 +28,3 @@ FROM base as production
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=build-and-test ./nitro-web/node_modules ./node_modules
|
||||
COPY --from=build-and-test ./nitro-web/.nuxt ./.nuxt
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["yarn", "run", "start"]
|
||||
|
||||
@ -15,6 +15,12 @@ $ yarn styleguide:build
|
||||
$ yarn install
|
||||
```
|
||||
|
||||
Copy:
|
||||
```
|
||||
cp .env.template .env
|
||||
```
|
||||
Configure the file `.env` according to your needs and your local setup.
|
||||
|
||||
### Development
|
||||
``` bash
|
||||
# serve with hot reload at localhost:3000
|
||||
|
||||
@ -54,9 +54,20 @@
|
||||
<hc-badges
|
||||
v-if="author.badges && author.badges.length"
|
||||
:badges="author.badges"
|
||||
style="margin-bottom: -10px"
|
||||
/>
|
||||
<ds-flex>
|
||||
<ds-text
|
||||
v-if="author.location"
|
||||
align="center"
|
||||
color="soft"
|
||||
size="small"
|
||||
style="margin-top: 5px"
|
||||
bold
|
||||
>
|
||||
<ds-icon name="map-marker" /> {{ author.location.name }}
|
||||
</ds-text>
|
||||
<ds-flex
|
||||
style="margin-top: -10px"
|
||||
>
|
||||
<ds-flex-item class="ds-tab-nav-item">
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
ghost
|
||||
@click="$emit('click')"
|
||||
>
|
||||
mehr laden
|
||||
{{ $t('actions.loadMore') }}
|
||||
</ds-button>
|
||||
</ds-space>
|
||||
</template>
|
||||
|
||||
@ -41,11 +41,13 @@
|
||||
</div>
|
||||
<div style="display: inline-block; float: right">
|
||||
<span :style="{ opacity: post.shoutedCount ? 1 : .5 }">
|
||||
<ds-icon name="bullhorn" /> <small>{{ post.shoutedCount }}</small>
|
||||
<ds-icon name="bullhorn" />
|
||||
<small>{{ post.shoutedCount }}</small>
|
||||
</span>
|
||||
|
||||
<span :style="{ opacity: post.commentsCount ? 1 : .5 }">
|
||||
<ds-icon name="comments" /> <small>{{ post.commentsCount }}</small>
|
||||
<ds-icon name="comments" />
|
||||
<small>{{ post.commentsCount }}</small>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"projectId": "qa7fe2",
|
||||
"ignoreTestFiles": "*.js"
|
||||
"ignoreTestFiles": "*.js",
|
||||
"baseUrl": "http://localhost:3000"
|
||||
}
|
||||
|
||||
@ -5,8 +5,10 @@ Feature: Authentication
|
||||
|
||||
Background:
|
||||
Given my account has the following details:
|
||||
| name | email | password |
|
||||
| Peter Lustig | admin@example.org | 1234 |
|
||||
| name | email | password | type
|
||||
| Peter Lustig | admin@example.org | 1234 | Admin
|
||||
| Bob der Bausmeister | moderator@example.org | 1234 | Moderator
|
||||
| Jenny Rostock" | user@example.org | 1234 | User
|
||||
|
||||
Scenario: Log in
|
||||
When I visit the "/login" page
|
||||
@ -13,12 +13,11 @@ Feature: Internationalization
|
||||
|
||||
Examples: Login Button
|
||||
| language | buttonLabel |
|
||||
| English | Login |
|
||||
| Deutsch | Einloggen |
|
||||
| Français | Connexion |
|
||||
| Nederlands | Inloggen |
|
||||
| Deutsch | Einloggen |
|
||||
| English | Login |
|
||||
|
||||
Scenario: Keep preferred language after refresh
|
||||
Given I previously switched the language to "Deutsch"
|
||||
Given I previously switched the language to "Français"
|
||||
And I refresh the page
|
||||
Then the whole user interface appears in "Deutsch"
|
||||
Then the whole user interface appears in "Français"
|
||||
45
cypress/integration/04.AboutMeAndLocation.feature
Normal file
45
cypress/integration/04.AboutMeAndLocation.feature
Normal file
@ -0,0 +1,45 @@
|
||||
Feature: About me and and location
|
||||
As a user
|
||||
I would like to add some about me text and a location
|
||||
So others can get some info about me and my location
|
||||
|
||||
The location and about me are displayed on the user profile. Later it will be possible
|
||||
to search for users by location.
|
||||
|
||||
Background:
|
||||
Given I am logged in
|
||||
And I am on the "settings" page
|
||||
|
||||
Scenario: Change username
|
||||
When I save "Hansi" as my new name
|
||||
Then I can see my new name "Hansi" when I click on my profile picture in the top right
|
||||
|
||||
Scenario: Keep changes after refresh
|
||||
When I changed my username to "Hansi" previously
|
||||
And I refresh the page
|
||||
Then my new username is still there
|
||||
|
||||
Scenario Outline: I set my location to "<location>"
|
||||
When I save "<location>" as my location
|
||||
And my username is "Peter Lustig"
|
||||
When people visit my profile page
|
||||
Then they can see the location in the info box below my avatar
|
||||
|
||||
Examples: Location
|
||||
| location | type |
|
||||
| Paris | City |
|
||||
| Saxony-Anhalt | Region |
|
||||
| Germany | Country |
|
||||
|
||||
Scenario: Display a description on profile page
|
||||
Given I have the following self-description:
|
||||
"""
|
||||
Ich lebe fettlos, fleischlos, fischlos dahin, fühle mich aber ganz wohl dabei
|
||||
"""
|
||||
And my username is "Peter Lustig"
|
||||
When people visit my profile page
|
||||
Then they can see the text in the info box below my avatar
|
||||
|
||||
|
||||
|
||||
|
||||
39
cypress/integration/common/admin.js
Normal file
39
cypress/integration/common/admin.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
/* global cy */
|
||||
|
||||
const lastColumnIsSortedInDescendingOrder = () => {
|
||||
cy.get('tbody')
|
||||
.find('tr td:last-child')
|
||||
.then(lastColumn => {
|
||||
cy.wrap(lastColumn)
|
||||
const values = lastColumn
|
||||
.map((i, td) => parseInt(td.textContent))
|
||||
.toArray()
|
||||
const orderedDescending = values.slice(0).sort((a, b) => b - a)
|
||||
return cy.wrap(values).should('deep.eq', orderedDescending)
|
||||
})
|
||||
}
|
||||
|
||||
When('I navigate to the administration dashboard', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.find('a[href="/admin"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
Then('I can see a list of categories ordered by post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 3)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
})
|
||||
|
||||
Then('I can see a list of tags ordered by user and post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 4)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
})
|
||||
76
cypress/integration/common/settings.js
Normal file
76
cypress/integration/common/settings.js
Normal file
@ -0,0 +1,76 @@
|
||||
import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
/* global cy */
|
||||
|
||||
let aboutMeText
|
||||
let myLocation
|
||||
let myName
|
||||
|
||||
const matchNameInUserMenu = name => {
|
||||
cy.get('.avatar-menu').click() // open
|
||||
cy.get('.avatar-menu-popover').contains(name)
|
||||
cy.get('.avatar-menu').click() // close again
|
||||
}
|
||||
|
||||
const setUserName = name => {
|
||||
cy.get('input[id=name]')
|
||||
.clear()
|
||||
.type(name)
|
||||
cy.contains('Save')
|
||||
.click()
|
||||
.wait(200)
|
||||
myName = name
|
||||
}
|
||||
|
||||
When('I save {string} as my new name', name => {
|
||||
setUserName(name)
|
||||
})
|
||||
|
||||
When('I save {string} as my location', location => {
|
||||
cy.get('input[id=city]').type(location)
|
||||
cy.get('.ds-select-option')
|
||||
.contains(location)
|
||||
.click()
|
||||
cy.contains('Save').click()
|
||||
myLocation = location
|
||||
})
|
||||
|
||||
When('I have the following self-description:', text => {
|
||||
cy.get('textarea[id=bio]')
|
||||
.clear()
|
||||
.type(text)
|
||||
cy.contains('Save').click()
|
||||
aboutMeText = text
|
||||
})
|
||||
|
||||
When('my username is {string}', name => {
|
||||
if (myName !== name) {
|
||||
setUserName(name)
|
||||
}
|
||||
matchNameInUserMenu(name)
|
||||
})
|
||||
|
||||
When('people visit my profile page', url => {
|
||||
cy.visitMyProfile()
|
||||
})
|
||||
|
||||
When('they can see the text in the info box below my avatar', () => {
|
||||
cy.contains(aboutMeText)
|
||||
})
|
||||
|
||||
When('I changed my username to {string} previously', name => {
|
||||
myName = name
|
||||
})
|
||||
|
||||
Then('they can see the location in the info box below my avatar', () => {
|
||||
matchNameInUserMenu(myName)
|
||||
})
|
||||
|
||||
Then('my new username is still there', () => {
|
||||
matchNameInUserMenu(myName)
|
||||
})
|
||||
|
||||
Then(
|
||||
'I can see my new name {string} when I click on my profile picture in the top right',
|
||||
name => matchNameInUserMenu(name)
|
||||
)
|
||||
@ -1,63 +1,20 @@
|
||||
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
import { getLangByName } from '../../support/helpers'
|
||||
import find from 'lodash/find'
|
||||
|
||||
/* global cy */
|
||||
/* global cy */
|
||||
|
||||
const baseUrl = 'http://localhost:3000'
|
||||
const username = 'Peter Lustig'
|
||||
|
||||
const locales = require('../../../locales')
|
||||
|
||||
const getLangByName = function(name) {
|
||||
return find(locales, { name })
|
||||
}
|
||||
|
||||
const openPage = function(page) {
|
||||
const openPage = page => {
|
||||
if (page === 'landing') {
|
||||
page = ''
|
||||
}
|
||||
cy.visit(`${baseUrl}/${page}`)
|
||||
}
|
||||
|
||||
const switchLanguage = function(name) {
|
||||
cy.get('.login-locale-switch a').click()
|
||||
cy.contains('.locale-menu-popover a', name).click()
|
||||
}
|
||||
|
||||
const login = (email, password) => {
|
||||
cy.visit(`${baseUrl}/login`)
|
||||
cy.get('input[name=email]')
|
||||
.trigger('focus')
|
||||
.type(email)
|
||||
cy.get('input[name=password]')
|
||||
.trigger('focus')
|
||||
.type(password)
|
||||
cy.get('button[name=submit]')
|
||||
.as('submitButton')
|
||||
.click()
|
||||
cy.location('pathname').should('eq', '/') // we're in!
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
cy.visit(`${baseUrl}/logout`)
|
||||
cy.location('pathname').should('contain', '/login') // we're out
|
||||
}
|
||||
|
||||
const lastColumnIsSortedInDescendingOrder = () => {
|
||||
cy.get('tbody')
|
||||
.find('tr td:last-child')
|
||||
.then(last_column => {
|
||||
cy.wrap(last_column)
|
||||
const values = last_column
|
||||
.map((i, td) => parseInt(td.textContent))
|
||||
.toArray()
|
||||
const ordered_descending = values.slice(0).sort((a, b) => b - a)
|
||||
return cy.wrap(values).should('deep.eq', ordered_descending)
|
||||
})
|
||||
cy.visit(`/${page}`)
|
||||
}
|
||||
|
||||
Given('I am logged in', () => {
|
||||
login('admin@example.org', 1234)
|
||||
cy.login('admin@example.org', 1234)
|
||||
})
|
||||
|
||||
Given('we have a selection of tags and categories as well as posts', () => {
|
||||
@ -72,7 +29,7 @@ Given('my user account has the role {string}', role => {
|
||||
// TODO: use db factories instead of seed data
|
||||
})
|
||||
|
||||
When('I log out', logout)
|
||||
When('I log out', cy.logout)
|
||||
|
||||
When('I visit the {string} page', page => {
|
||||
openPage(page)
|
||||
@ -82,7 +39,7 @@ Given('I am on the {string} page', page => {
|
||||
})
|
||||
|
||||
When('I fill in my email and password combination and click submit', () => {
|
||||
login('admin@example.org', 1234)
|
||||
cy.login('admin@example.org', 1234)
|
||||
})
|
||||
|
||||
When('I refresh the page', () => {
|
||||
@ -92,8 +49,7 @@ When('I refresh the page', () => {
|
||||
When('I log out through the menu in the top right corner', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.find('a')
|
||||
.contains('Logout')
|
||||
.find('a[href="/logout"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
@ -108,7 +64,6 @@ Then('I can see my name {string} in the dropdown menu', () => {
|
||||
|
||||
Then('I see the login screen again', () => {
|
||||
cy.location('pathname').should('contain', '/login')
|
||||
cy.contains('If you already have a human-connection account, login here.')
|
||||
})
|
||||
|
||||
Then('I am still logged in', () => {
|
||||
@ -117,10 +72,10 @@ Then('I am still logged in', () => {
|
||||
})
|
||||
|
||||
When('I select {string} in the language menu', name => {
|
||||
switchLanguage(name)
|
||||
cy.switchLanguage(name, true)
|
||||
})
|
||||
Given('I previously switched the language to {string}', name => {
|
||||
switchLanguage(name)
|
||||
cy.switchLanguage(name, true)
|
||||
})
|
||||
Then('the whole user interface appears in {string}', name => {
|
||||
const lang = getLangByName(name)
|
||||
@ -131,29 +86,10 @@ Then('I see a button with the label {string}', label => {
|
||||
cy.contains('button', label)
|
||||
})
|
||||
|
||||
When('I navigate to the administration dashboard', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.contains('Admin')
|
||||
.click()
|
||||
})
|
||||
|
||||
When(`I click on {string}`, linkOrButton => {
|
||||
cy.contains(linkOrButton).click()
|
||||
})
|
||||
|
||||
Then('I can see a list of categories ordered by post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 3)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
})
|
||||
|
||||
Then('I can see a list of tags ordered by user and post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 4)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
When('I press {string}', label => {
|
||||
cy.contains(label).click()
|
||||
})
|
||||
|
||||
@ -10,16 +10,64 @@
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
|
||||
/* globals Cypress cy */
|
||||
|
||||
import { getLangByName } from './helpers'
|
||||
|
||||
const switchLang = name => {
|
||||
cy.get('.locale-menu').click()
|
||||
cy.contains('.locale-menu-popover a', name).click()
|
||||
}
|
||||
|
||||
Cypress.Commands.add('switchLanguage', (name, force) => {
|
||||
const code = getLangByName(name).code
|
||||
if (force) {
|
||||
switchLang(name)
|
||||
} else {
|
||||
cy.get('html').then($html => {
|
||||
if ($html && $html.attr('lang') !== code) {
|
||||
switchLang(name)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Cypress.Commands.add('visitMyProfile', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.find('a[href^="/profile/"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
Cypress.Commands.add('login', (email, password) => {
|
||||
cy.visit(`/login`)
|
||||
cy.get('input[name=email]')
|
||||
.trigger('focus')
|
||||
.type(email)
|
||||
cy.get('input[name=password]')
|
||||
.trigger('focus')
|
||||
.type(password)
|
||||
cy.get('button[name=submit]')
|
||||
.as('submitButton')
|
||||
.click()
|
||||
cy.location('pathname').should('eq', '/') // we're in!
|
||||
})
|
||||
Cypress.Commands.add('logout', (email, password) => {
|
||||
cy.visit(`/logout`)
|
||||
cy.location('pathname').should('contain', '/login') // we're out
|
||||
})
|
||||
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
|
||||
16
cypress/support/config.js
Normal file
16
cypress/support/config.js
Normal file
@ -0,0 +1,16 @@
|
||||
export default {
|
||||
users: {
|
||||
admin: {
|
||||
email: 'admin@example.org',
|
||||
password: 1234
|
||||
},
|
||||
moderator: {
|
||||
email: 'moderator@example.org',
|
||||
password: 1234
|
||||
},
|
||||
user: {
|
||||
email: 'user@example.org',
|
||||
password: 1234
|
||||
}
|
||||
}
|
||||
}
|
||||
11
cypress/support/helpers.js
Normal file
11
cypress/support/helpers.js
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
import find from 'lodash/find'
|
||||
|
||||
const helpers = {
|
||||
locales: require('../../locales'),
|
||||
getLangByName: name => {
|
||||
return find(helpers.locales, { name })
|
||||
}
|
||||
}
|
||||
|
||||
export default helpers
|
||||
@ -14,6 +14,8 @@ services:
|
||||
environment:
|
||||
- HOST=0.0.0.0
|
||||
- BACKEND_URL=http://backend:4000
|
||||
- JWT_SECRET="b/&&7b78BF&fv/Vd"
|
||||
- MAPBOX_TOKEN="pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.bZ8KK9l70omjXbEkkbHGsQ"
|
||||
|
||||
networks:
|
||||
hc-network:
|
||||
|
||||
@ -1,72 +1,89 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default gql(`
|
||||
query User($slug: String!, $first: Int, $offset: Int) {
|
||||
User(slug: $slug) {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
createdAt
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
badgesCount
|
||||
shoutedCount
|
||||
commentsCount
|
||||
followingCount
|
||||
following(first: 7) {
|
||||
export default app => {
|
||||
const lang = app.$i18n.locale().toUpperCase()
|
||||
return gql(`
|
||||
query User($slug: String!, $first: Int, $offset: Int) {
|
||||
User(slug: $slug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
avatar
|
||||
followedByCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
about
|
||||
locationName
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
createdAt
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
followedByCount
|
||||
followedBy(first: 7) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
avatar
|
||||
followedByCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
contributionsCount
|
||||
contributions(first: $first, offset: $offset, orderBy: createdAt_desc) {
|
||||
id
|
||||
slug
|
||||
title
|
||||
contentExcerpt
|
||||
badgesCount
|
||||
shoutedCount
|
||||
commentsCount
|
||||
deleted
|
||||
image
|
||||
createdAt
|
||||
categories {
|
||||
followingCount
|
||||
following(first: 7) {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
author {
|
||||
id
|
||||
slug
|
||||
avatar
|
||||
followedByCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
}
|
||||
followedByCount
|
||||
followedBy(first: 7) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
avatar
|
||||
followedByCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
}
|
||||
contributionsCount
|
||||
contributions(first: $first, offset: $offset, orderBy: createdAt_desc) {
|
||||
id
|
||||
slug
|
||||
title
|
||||
contentExcerpt
|
||||
shoutedCount
|
||||
commentsCount
|
||||
deleted
|
||||
image
|
||||
createdAt
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
author {
|
||||
id
|
||||
avatar
|
||||
name
|
||||
location {
|
||||
name: name${lang}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
`)
|
||||
}
|
||||
|
||||
@ -47,6 +47,15 @@
|
||||
>
|
||||
<div class="avatar-menu-popover">
|
||||
{{ $t('login.hello') }} <b>{{ user.name }}</b>
|
||||
<template v-if="user.role !== 'user'">
|
||||
<ds-text
|
||||
color="softer"
|
||||
size="small"
|
||||
style="margin-bottom: 0"
|
||||
>
|
||||
{{ user.role | camelCase }}
|
||||
</ds-text>
|
||||
</template>
|
||||
<hr>
|
||||
<ds-menu
|
||||
:routes="routes"
|
||||
|
||||
@ -1,4 +1,12 @@
|
||||
{
|
||||
"actions": {
|
||||
"loading": "lade",
|
||||
"loadMore": "mehr laden",
|
||||
"create": "Erstellen",
|
||||
"save": "Speichern",
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"login": {
|
||||
"copy": "Wenn Du bereits ein Konto bei Human Connection hast, melde Dich bitte hier an.",
|
||||
"login": "Einloggen",
|
||||
@ -20,7 +28,10 @@
|
||||
"settings": {
|
||||
"name": "Einstellungen",
|
||||
"data": {
|
||||
"name": "Deine Daten"
|
||||
"name": "Deine Daten",
|
||||
"labelName": "Dein Name",
|
||||
"labelCity": "Deine Stadt oder Region",
|
||||
"labelBio": "Über dich"
|
||||
},
|
||||
"security": {
|
||||
"name": "Sicherheit"
|
||||
|
||||
@ -1,4 +1,12 @@
|
||||
{
|
||||
"actions": {
|
||||
"loading": "loading",
|
||||
"loadMore": "load more",
|
||||
"create": "Create",
|
||||
"save": "Save",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete"
|
||||
},
|
||||
"login": {
|
||||
"copy": "If you already have a human-connection account, login here.",
|
||||
"login": "Login",
|
||||
@ -20,7 +28,10 @@
|
||||
"settings": {
|
||||
"name": "Settings",
|
||||
"data": {
|
||||
"name": "Your data"
|
||||
"name": "Your data",
|
||||
"labelName": "Your Name",
|
||||
"labelCity": "Your City or Region",
|
||||
"labelBio": "About You"
|
||||
},
|
||||
"security": {
|
||||
"name": "Security"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
const pkg = require('./package')
|
||||
const envWhitelist = ['NODE_ENV', 'MAINTENANCE']
|
||||
const envWhitelist = ['NODE_ENV', 'MAINTENANCE', 'MAPBOX_TOKEN']
|
||||
const dev = process.env.NODE_ENV !== 'production'
|
||||
const path = require('path')
|
||||
|
||||
@ -62,6 +62,7 @@ module.exports = {
|
||||
*/
|
||||
plugins: [
|
||||
{ src: '~/plugins/i18n.js', ssr: true },
|
||||
{ src: '~/plugins/axios.js', ssr: false },
|
||||
{ src: '~/plugins/keep-alive.js', ssr: false },
|
||||
{ src: '~/plugins/design-system.js', ssr: true },
|
||||
{ src: '~/plugins/vue-directives.js', ssr: false },
|
||||
|
||||
@ -79,40 +79,45 @@ export default {
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query: gql(`
|
||||
query Post($first: Int, $offset: Int) {
|
||||
Post(first: $first, offset: $offset) {
|
||||
id
|
||||
title
|
||||
contentExcerpt
|
||||
createdAt
|
||||
slug
|
||||
image
|
||||
author {
|
||||
query() {
|
||||
return gql(`
|
||||
query Post($first: Int, $offset: Int) {
|
||||
Post(first: $first, offset: $offset) {
|
||||
id
|
||||
avatar
|
||||
title
|
||||
contentExcerpt
|
||||
createdAt
|
||||
slug
|
||||
name
|
||||
contributionsCount
|
||||
shoutedCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
badges {
|
||||
image
|
||||
author {
|
||||
id
|
||||
key
|
||||
avatar
|
||||
slug
|
||||
name
|
||||
contributionsCount
|
||||
shoutedCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
location {
|
||||
name: name${this.$i18n.locale().toUpperCase()}
|
||||
}
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
commentsCount
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
commentsCount
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
}
|
||||
`),
|
||||
`)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
first: this.pageSize,
|
||||
|
||||
@ -141,39 +141,16 @@ export default {
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query: gql(`
|
||||
query Post($slug: String!) {
|
||||
Post(slug: $slug) {
|
||||
id
|
||||
title
|
||||
content
|
||||
createdAt
|
||||
slug
|
||||
image
|
||||
author {
|
||||
query() {
|
||||
return gql(`
|
||||
query Post($slug: String!) {
|
||||
Post(slug: $slug) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
avatar
|
||||
shoutedCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
tags {
|
||||
name
|
||||
}
|
||||
commentsCount
|
||||
comments(orderBy: createdAt_desc) {
|
||||
id
|
||||
contentExcerpt
|
||||
title
|
||||
content
|
||||
createdAt
|
||||
deleted
|
||||
slug
|
||||
image
|
||||
author {
|
||||
id
|
||||
slug
|
||||
@ -183,22 +160,53 @@ export default {
|
||||
contributionsCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
location {
|
||||
name: name${this.$i18n.locale().toUpperCase()}
|
||||
}
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
tags {
|
||||
name
|
||||
}
|
||||
commentsCount
|
||||
comments(orderBy: createdAt_desc) {
|
||||
id
|
||||
contentExcerpt
|
||||
createdAt
|
||||
deleted
|
||||
author {
|
||||
id
|
||||
slug
|
||||
name
|
||||
avatar
|
||||
shoutedCount
|
||||
contributionsCount
|
||||
commentsCount
|
||||
followedByCount
|
||||
location {
|
||||
name: name${this.$i18n.locale().toUpperCase()}
|
||||
}
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
}
|
||||
`),
|
||||
`)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
slug: this.$route.params.slug
|
||||
|
||||
@ -7,13 +7,16 @@
|
||||
<ds-space />
|
||||
<h3><ds-icon name="compass" /> Themenkategorien</h3>
|
||||
<div class="tags">
|
||||
<ds-tag
|
||||
<ds-icon
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"
|
||||
v-tooltip="{content: category.name, placement: 'top-start', delay: { show: 300 }}"
|
||||
>
|
||||
<ds-icon :name="category.icon" /> {{ category.name }}
|
||||
</ds-tag>
|
||||
:name="category.icon"
|
||||
size="large"
|
||||
/>
|
||||
<!--<ds-tag
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"><ds-icon :name="category.icon" /> {{ category.name }}</ds-tag>-->
|
||||
</div>
|
||||
<template v-if="post.tags && post.tags.length">
|
||||
<h3><ds-icon name="tags" /> Schlagwörter</h3>
|
||||
@ -70,51 +73,56 @@ export default {
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query: gql(`
|
||||
query Post($slug: String!) {
|
||||
Post(slug: $slug) {
|
||||
id
|
||||
title
|
||||
tags {
|
||||
id
|
||||
name
|
||||
}
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
relatedContributions(first: 2) {
|
||||
query() {
|
||||
return gql(`
|
||||
query Post($slug: String!) {
|
||||
Post(slug: $slug) {
|
||||
id
|
||||
title
|
||||
slug
|
||||
contentExcerpt
|
||||
shoutedCount
|
||||
commentsCount
|
||||
tags {
|
||||
id
|
||||
name
|
||||
}
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
author {
|
||||
relatedContributions(first: 2) {
|
||||
id
|
||||
name
|
||||
title
|
||||
slug
|
||||
avatar
|
||||
contributionsCount
|
||||
followedByCount
|
||||
contentExcerpt
|
||||
shoutedCount
|
||||
commentsCount
|
||||
badges {
|
||||
categories {
|
||||
id
|
||||
key
|
||||
name
|
||||
icon
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
slug
|
||||
avatar
|
||||
contributionsCount
|
||||
followedByCount
|
||||
commentsCount
|
||||
location {
|
||||
name: name${this.$i18n.locale().toUpperCase()}
|
||||
}
|
||||
badges {
|
||||
id
|
||||
key
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
}
|
||||
`),
|
||||
`)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
slug: this.$route.params.slug
|
||||
|
||||
@ -25,6 +25,14 @@
|
||||
>
|
||||
{{ user.name }}
|
||||
</ds-heading>
|
||||
<ds-text
|
||||
v-if="user.location"
|
||||
align="center"
|
||||
color="soft"
|
||||
size="small"
|
||||
>
|
||||
<ds-icon name="map-marker" /> {{ user.location.name }}
|
||||
</ds-text>
|
||||
<ds-text
|
||||
align="center"
|
||||
color="soft"
|
||||
@ -72,6 +80,20 @@
|
||||
@update="voted = true && fetchUser()"
|
||||
/>
|
||||
</ds-space>
|
||||
<template v-if="user.about">
|
||||
<hr>
|
||||
<ds-space
|
||||
margin-top="small"
|
||||
margin-bottom="small"
|
||||
>
|
||||
<ds-text
|
||||
color="soft"
|
||||
size="small"
|
||||
>
|
||||
{{ user.about }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
</template>
|
||||
</ds-card>
|
||||
<ds-space />
|
||||
<ds-heading
|
||||
@ -176,7 +198,7 @@
|
||||
:width="{ base: '100%' }"
|
||||
gutter="small"
|
||||
>
|
||||
<ds-flex-item>
|
||||
<ds-flex-item class="profile-top-navigation">
|
||||
<ds-card class="ds-tab-nav">
|
||||
<ds-flex>
|
||||
<ds-flex-item class="ds-tab-nav-item ds-tab-nav-item-active">
|
||||
@ -338,7 +360,9 @@ export default {
|
||||
},
|
||||
apollo: {
|
||||
User: {
|
||||
query: require('~/graphql/UserProfileQuery.js').default,
|
||||
query() {
|
||||
return require('~/graphql/UserProfileQuery.js').default(this)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
slug: this.$route.params.slug,
|
||||
@ -360,6 +384,12 @@ export default {
|
||||
border: #fff 5px solid;
|
||||
}
|
||||
|
||||
.profile-top-navigation {
|
||||
position: sticky;
|
||||
top: 53px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ds-tab-nav {
|
||||
.ds-card-content {
|
||||
padding: 0 !important;
|
||||
|
||||
@ -1,7 +1,204 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
<ds-card space="small">
|
||||
<ds-heading tag="h3">
|
||||
{{ $t('settings.data.name') }}
|
||||
</ds-space>
|
||||
</ds-heading>
|
||||
<ds-input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
icon="user"
|
||||
:label="$t('settings.data.labelName')"
|
||||
:placeholder="$t('settings.data.labelName')"
|
||||
/>
|
||||
<!-- eslint-disable vue/use-v-on-exact -->
|
||||
<ds-select
|
||||
id="city"
|
||||
v-model="form.locationName"
|
||||
:options="cities"
|
||||
icon="map-marker"
|
||||
:label="$t('settings.data.labelCity')"
|
||||
:placeholder="$t('settings.data.labelCity')"
|
||||
@input.native="handleCityInput"
|
||||
/>
|
||||
<!-- eslint-enable vue/use-v-on-exact -->
|
||||
<ds-input
|
||||
id="bio"
|
||||
v-model="form.about"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
:label="$t('settings.data.labelBio')"
|
||||
:placeholder="$t('settings.data.labelBio')"
|
||||
/>
|
||||
<template slot="footer">
|
||||
<ds-button
|
||||
style="float: right;"
|
||||
icon="check"
|
||||
primary
|
||||
@click.prevent="submit"
|
||||
>
|
||||
{{ $t('actions.save') }}
|
||||
</ds-button>
|
||||
</template>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
import { CancelToken } from 'axios'
|
||||
import find from 'lodash/find'
|
||||
|
||||
let timeout
|
||||
const mapboxToken = process.env.MAPBOX_TOKEN
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
axiosSource: null,
|
||||
cities: [],
|
||||
form: {
|
||||
name: null,
|
||||
locationName: null,
|
||||
about: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
user: 'auth/user'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
user: {
|
||||
immediate: true,
|
||||
handler: function(user) {
|
||||
this.form = {
|
||||
name: user.name,
|
||||
locationName: user.locationName,
|
||||
about: user.about
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
console.log('SUBMIT', { ...this.form })
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: gql`
|
||||
mutation(
|
||||
$id: ID!
|
||||
$name: String
|
||||
$locationName: String
|
||||
$about: String
|
||||
) {
|
||||
UpdateUser(
|
||||
id: $id
|
||||
name: $name
|
||||
locationName: $locationName
|
||||
about: $about
|
||||
) {
|
||||
id
|
||||
name
|
||||
locationName
|
||||
about
|
||||
}
|
||||
}
|
||||
`,
|
||||
// Parameters
|
||||
variables: {
|
||||
id: this.user.id,
|
||||
name: this.form.name,
|
||||
locationName: this.form.locationName,
|
||||
about: this.form.about
|
||||
},
|
||||
// Update the cache with the result
|
||||
// The query will be updated with the optimistic response
|
||||
// and then with the real result of the mutation
|
||||
update: (store, { data: { UpdateUser } }) => {
|
||||
this.$store.dispatch('auth/fetchCurrentUser')
|
||||
|
||||
// Read the data from our cache for this query.
|
||||
// const data = store.readQuery({ query: TAGS_QUERY })
|
||||
// Add our tag from the mutation to the end
|
||||
// data.tags.push(addTag)
|
||||
// Write our data back to the cache.
|
||||
// store.writeQuery({ query: TAGS_QUERY, data })
|
||||
}
|
||||
// Optimistic UI
|
||||
// Will be treated as a 'fake' result as soon as the request is made
|
||||
// so that the UI can react quickly and the user be happy
|
||||
/* optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
addTag: {
|
||||
__typename: 'Tag',
|
||||
id: -1,
|
||||
label: newTag
|
||||
}
|
||||
} */
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
this.$toast.success('Updated user')
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
this.$toast.error(err.message)
|
||||
})
|
||||
},
|
||||
handleCityInput(value) {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => this.requestGeoData(value), 500)
|
||||
},
|
||||
processCityResults(res) {
|
||||
if (
|
||||
!res ||
|
||||
!res.data ||
|
||||
!res.data.features ||
|
||||
!res.data.features.length
|
||||
) {
|
||||
return []
|
||||
}
|
||||
let output = []
|
||||
res.data.features.forEach(item => {
|
||||
output.push({
|
||||
label: item.place_name,
|
||||
value: item.place_name,
|
||||
id: item.id
|
||||
})
|
||||
})
|
||||
|
||||
return output
|
||||
},
|
||||
requestGeoData(e) {
|
||||
if (this.axiosSource) {
|
||||
// cancel last request
|
||||
this.axiosSource.cancel()
|
||||
}
|
||||
|
||||
const value = e.target ? e.target.value.trim() : ''
|
||||
if (value === '' || value.length < 3) {
|
||||
this.cities = []
|
||||
return
|
||||
}
|
||||
|
||||
this.axiosSource = CancelToken.source()
|
||||
|
||||
const place = encodeURIComponent(value)
|
||||
const lang = this.$i18n.locale()
|
||||
|
||||
this.$axios
|
||||
.get(
|
||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${mapboxToken}&types=region,place,country&language=${lang}`,
|
||||
{
|
||||
cancelToken: this.axiosSource.token
|
||||
}
|
||||
)
|
||||
.then(res => {
|
||||
this.cities = this.processCityResults(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export default function({ app }) {
|
||||
export default ({ app }) => {
|
||||
const backendUrl = process.env.BACKEND_URL || 'http://localhost:4000'
|
||||
return {
|
||||
httpEndpoint: process.server ? backendUrl : '/api',
|
||||
|
||||
7
plugins/axios.js
Normal file
7
plugins/axios.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default ({ $axios, app }) => {
|
||||
$axios.onRequest(config => {
|
||||
console.log(Object.keys(app))
|
||||
// add current ui language
|
||||
config.headers['Accept-Language'] = app.$i18n.locale()
|
||||
})
|
||||
}
|
||||
@ -67,9 +67,12 @@ export default ({ app, req, cookie, store }) => {
|
||||
if (!isEmpty(localeCookie)) {
|
||||
userLocale = localeCookie
|
||||
} else {
|
||||
userLocale = process.browser
|
||||
? navigator.language || navigator.userLanguage
|
||||
: req.locale
|
||||
try {
|
||||
userLocale = process.browser
|
||||
? navigator.language || navigator.userLanguage
|
||||
: req.headers['accept-language'].split(',')[0]
|
||||
} catch (err) {}
|
||||
|
||||
if (userLocale && !isEmpty(userLocale.language)) {
|
||||
userLocale = userLocale.language.substr(0, 2)
|
||||
}
|
||||
|
||||
@ -2,27 +2,30 @@ import Vue from 'vue'
|
||||
|
||||
let lastRoute
|
||||
const keepAliveHook = {}
|
||||
keepAliveHook.install = Vue => {
|
||||
const keepAlivePages = process.env.keepAlivePages || []
|
||||
|
||||
Vue.mixin({
|
||||
// Save route if this instance is a page (has metaInfo)
|
||||
mounted() {
|
||||
if (this.$metaInfo) {
|
||||
lastRoute = this.$route.name
|
||||
if (!process.server) {
|
||||
keepAliveHook.install = Vue => {
|
||||
const keepAlivePages = process.env.keepAlivePages || []
|
||||
|
||||
Vue.mixin({
|
||||
// Save route if this instance is a page (has metaInfo)
|
||||
mounted() {
|
||||
if (this.$metaInfo) {
|
||||
lastRoute = this.$route.name
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
if (this.$metaInfo) {
|
||||
lastRoute = this.$route.name
|
||||
}
|
||||
},
|
||||
deactivated() {
|
||||
// If this is a page and we don't want it to be kept alive
|
||||
if (this.$metaInfo && !keepAlivePages.includes(lastRoute)) {
|
||||
this.$destroy()
|
||||
}
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
if (this.$metaInfo) {
|
||||
lastRoute = this.$route.name
|
||||
}
|
||||
},
|
||||
deactivated() {
|
||||
// If this is a page and we don't want it to be kept alive
|
||||
if (this.$metaInfo && !keepAlivePages.includes(lastRoute)) {
|
||||
this.$destroy()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
Vue.use(keepAliveHook)
|
||||
}
|
||||
Vue.use(keepAliveHook)
|
||||
|
||||
@ -2,9 +2,11 @@ const express = require('express')
|
||||
const consola = require('consola')
|
||||
const { Nuxt, Builder } = require('nuxt')
|
||||
const app = express()
|
||||
|
||||
require('dotenv').config()
|
||||
|
||||
const host = process.env.HOST || '127.0.0.1'
|
||||
const port = process.env.PORT || 3000
|
||||
|
||||
app.set('port', port)
|
||||
|
||||
// Import and Set Nuxt.js options
|
||||
|
||||
@ -49,8 +49,8 @@ export const getters = {
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
async init({ commit }) {
|
||||
if (process.client) {
|
||||
async init({ commit, dispatch }) {
|
||||
if (!process.server) {
|
||||
return
|
||||
}
|
||||
const token = this.app.$apolloHelpers.getToken()
|
||||
@ -58,18 +58,15 @@ export const actions = {
|
||||
return
|
||||
}
|
||||
|
||||
const user = await jwt.verify(token, 'b/&&7b78BF&fv/Vd')
|
||||
if (user.id) {
|
||||
commit('SET_USER', {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
slug: user.slug,
|
||||
email: user.email,
|
||||
avatar: user.avatar,
|
||||
role: user.role
|
||||
})
|
||||
commit('SET_TOKEN', token)
|
||||
const payload = await jwt.verify(token, process.env.JWT_SECRET)
|
||||
if (!payload.id) {
|
||||
return
|
||||
}
|
||||
commit('SET_TOKEN', token)
|
||||
commit('SET_USER', {
|
||||
id: payload.id
|
||||
})
|
||||
await dispatch('fetchCurrentUser')
|
||||
},
|
||||
async check({ commit, dispatch, getters }) {
|
||||
if (!this.app.$apolloHelpers.getToken()) {
|
||||
@ -77,24 +74,53 @@ export const actions = {
|
||||
}
|
||||
return getters.isLoggedIn
|
||||
},
|
||||
async login({ commit }, { email, password }) {
|
||||
commit('SET_PENDING', true)
|
||||
try {
|
||||
const res = await this.app.apolloProvider.defaultClient
|
||||
.mutate({
|
||||
mutation: gql(`
|
||||
mutation($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password) {
|
||||
async fetchCurrentUser({ commit, getters }) {
|
||||
await this.app.apolloProvider.defaultClient
|
||||
.query({
|
||||
query: gql(`
|
||||
query User($id: ID!) {
|
||||
User(id: $id) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
email
|
||||
avatar
|
||||
role
|
||||
token
|
||||
locationName
|
||||
about
|
||||
}
|
||||
}
|
||||
`),
|
||||
variables: { id: getters.user.id }
|
||||
})
|
||||
.then(({ data }) => {
|
||||
const user = data.User.pop()
|
||||
if (user.id && user.email) {
|
||||
commit('SET_USER', user)
|
||||
}
|
||||
})
|
||||
return getters.user
|
||||
},
|
||||
async login({ commit }, { email, password }) {
|
||||
commit('SET_PENDING', true)
|
||||
try {
|
||||
const res = await this.app.apolloProvider.defaultClient
|
||||
.mutate({
|
||||
mutation: gql(`
|
||||
mutation($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
email
|
||||
avatar
|
||||
role
|
||||
locationName
|
||||
about
|
||||
token
|
||||
}
|
||||
}
|
||||
`),
|
||||
variables: { email, password }
|
||||
})
|
||||
.then(({ data }) => data && data.login)
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
"vue-router": "^3.0.1",
|
||||
"vue-svg-loader": "^0.8.0",
|
||||
"vue-template-compiler": "^2.5.17",
|
||||
"vuep": "git://github.com/visualjerk/vuep.git#fix-iframe-firefox",
|
||||
"vuep": "git+https://github.com/visualjerk/vuep.git#fix-iframe-firefox",
|
||||
"webpack-bundle-analyzer": "^2.13.1",
|
||||
"webpack-merge-and-include-globally": "^2.0.11"
|
||||
},
|
||||
|
||||
@ -10629,9 +10629,9 @@ vue@^2.4.2, vue@^2.5.17:
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada"
|
||||
integrity sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==
|
||||
|
||||
"vuep@git://github.com/visualjerk/vuep.git#fix-iframe-firefox":
|
||||
"vuep@git+https://github.com/visualjerk/vuep.git#fix-iframe-firefox":
|
||||
version "0.8.1"
|
||||
resolved "git://github.com/visualjerk/vuep.git#df765f9bce3d96f79ffc35e75ec2885539bf9baa"
|
||||
resolved "git+https://github.com/visualjerk/vuep.git#df765f9bce3d96f79ffc35e75ec2885539bf9baa"
|
||||
dependencies:
|
||||
simple-assign "^0.1.0"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user