Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,92 @@
<template>
<section class="welcome-section">
<WelcomeFirst v-if="isFirst" :name="name" :userType="userType"></WelcomeFirst>
<WelcomeCompact v-if="!isFirst" :name="name" :userType="userType">
<template v-if="trialEndDate">
<span v-html="trialTimeLeft" class="title is-small"></span>
<a class="title is-small" :href="accountUpgradeURL" v-if="accountUpgradeURL">
{{ $t('HomePage.WelcomeSection.subscribeNow') }}
</a>
</template>
</WelcomeCompact>
</section>
</template>
<script>
import { mapState } from 'vuex';
import distanceInWordsStrict from 'date-fns/distance_in_words_strict';
import WelcomeCompact from './WelcomeCompact';
import WelcomeFirst from './WelcomeFirst';
import WelcomeBasic from './WelcomeBasic';
import { isOrganizationAdmin } from 'new-dashboard/core/models/organization';
export default {
name: 'Welcome',
components: {
WelcomeBasic,
WelcomeCompact,
WelcomeFirst
},
computed: {
...mapState({
isFirst: state => state.config.isFirstTimeViewingDashboard,
accountUpgradeURL: state => state.config.upgrade_url,
trialEndDate: state => state.user.trial_ends_at,
user: state => state.user,
name: state => state.user.name || state.user.username,
organization: state => state.user.organization,
notifications: state => state.user.organizationNotifications
}),
trialTimeLeft () {
return this.$t(`HomePage.WelcomeSection.trialMessage`, { date: distanceInWordsStrict(this.trialEndDate, new Date(), { partialMethod: 'round' }) });
},
userType () {
if (this.isOrganizationAdmin()) {
return 'organizationAdmin';
}
if (this.isOrganizationUser()) {
return 'organizationUser';
}
if (this.isIndividualUser()) {
return 'individual';
}
if (this.isPersonal30()) {
return '30day';
}
if (this.isFreeUser()) {
return 'free';
}
return 'unknown';
}
},
methods: {
isPersonal30 () {
const personal30User = ['PERSONAL30'];
return personal30User.includes(this.user.account_type);
},
isFreeUser () {
const freeUser = ['FREE'];
return freeUser.includes(this.user.account_type);
},
isIndividualUser () {
const individualUsers = ['Individual'];
return individualUsers.includes(this.user.account_type);
},
isOrganizationAdmin () {
if (!this.isOrganizationUser()) {
return false;
}
return isOrganizationAdmin(this.user.organization, this.user);
},
isOrganizationUser () {
return Boolean(this.organization);
}
}
};
</script>
@@ -0,0 +1,69 @@
<template>
<section class="welcome-basic">
<div class="container">
<div class="welcome-basic__greeting title is-title">{{ greeting }}</div>
<span v-if="hasNotifications" class="notification-led"></span>
<div class="welcome-basic__text text is-caption">{{ text }}</div>
<div class="welcome-basic__actions">
<button v-if="!hasNotifications" class="button button--small is-primary">Learn More</button>
<button v-if="hasNotifications" class="button button--small is-primary">Go to Notifications</button>
</div>
</div>
</section>
</template>
<script>
export default {
name: 'WelcomeBasic',
props: {
username: String,
notifications: Array
},
computed: {
greeting () {
return this.$t('HomePage.WelcomeSection.greeting', {username: this.$props.username});
},
text () {
return this.hasNotifications
? 'You have unread notifications, do you want to read them now?'
: 'We just released CARTO VL, our new vector rendering Javascript library to create amazing LI applications.';
},
hasNotifications () {
return this.$props.notifications.length > 0;
}
}
};
</script>
<style scoped lang="scss">
@import "new-dashboard/styles/variables";
.welcome-basic {
position: relative;
padding: 124px 0;
text-align: center;
.notification-led {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
background: $notification__bg-color;
vertical-align: top;
}
&__greeting {
display: inline-block;
}
&__text {
max-width: 724px;
margin: 16px auto 48px;
}
&__actions {
display: flex;
justify-content: center;
}
}
</style>
@@ -0,0 +1,88 @@
<template>
<section class="welcome-compact">
<div class="container welcome-compact__content">
<div class="welcome-compact__greeting title is-caption">{{ greeting }}</div>
<div class="welcome-compact__actions">
<OnboardingButton :isFirstTimeViewingDashboard="false"></OnboardingButton>
<CreateButton class="button--ghost" visualizationType="map" :disabled="isViewer">{{ $t(`HomePage.WelcomeSection.actions.createMap`) }}</CreateButton>
<CreateButton class="button--ghost" visualizationType="dataset" :disabled="!canCreateDatasets">{{ $t(`HomePage.WelcomeSection.actions.createDataset`) }}</CreateButton>
</div>
<div class="welcome-compact__extra">
<slot />
</div>
</div>
</section>
</template>
<script>
import CreateButton from 'new-dashboard/components/CreateButton.vue';
import OnboardingButton from 'new-dashboard/components/Onboarding/OnboardingButton.vue';
export default {
name: 'WelcomeCompact',
components: {
CreateButton,
OnboardingButton
},
props: {
name: String
},
computed: {
greeting () {
return this.$t('HomePage.WelcomeSection.greeting', {name: this.$props.name});
},
canCreateDatasets () {
return this.$store.getters['user/canCreateDatasets'];
},
isViewer () {
return this.$store.getters['user/isViewer'];
}
}
};
</script>
<style scoped lang="scss">
@import "new-dashboard/styles/variables";
.welcome-compact__content {
display: flex;
align-items: center;
max-width: 940px;
padding: 0;
}
.welcome-compact {
position: relative;
padding: 20px;
border-bottom: 1px solid #E6E8EB;
&__greeting {
display: inline-block;
margin-right: 64px;
}
&__actions {
display: inline-flex;
}
&__extra {
display: flex;
align-items: center;
margin-left: auto;
}
.button--ghost {
margin-right: 48px;
padding: 0;
background: none;
color: #047AE6;
text-transform: none;
}
.button--outline {
margin-left: 24px;
padding: 9px 16px;
}
}
</style>
@@ -0,0 +1,107 @@
<template>
<section class="welcome-first">
<div class="container">
<div class="welcome-first__greeting title is-title">{{ greeting }}</div>
<div class="welcome-first__text text is-caption" v-html="text"></div>
<div class="welcome-first__actions">
<OnboardingButton v-if="!isOrganizationAdmin" :isFirstTimeViewingDashboard="true"></OnboardingButton>
<a class="button button--border"
:href="`${ baseUrl }/organization`"
v-if="isOrganizationAdmin">
{{ $t('HomePage.WelcomeSection.firstTime.manageOrganization') }}
</a>
</div>
</div>
</section>
</template>
<script>
import differenceInDays from 'date-fns/difference_in_days';
import CreateButton from 'new-dashboard/components/CreateButton.vue';
import OnboardingButton from 'new-dashboard/components/Onboarding/OnboardingButton.vue';
export default {
name: 'WelcomeFirst',
components: {
CreateButton,
OnboardingButton
},
props: {
name: String,
userType: String
},
computed: {
greeting () {
return this.$t('HomePage.WelcomeSection.greeting', {name: this.$props.name});
},
text () {
const organizationName = this.$store.state.user.organization && this.$store.state.user.organization.name;
const firstTimeMessage = this.$t('HomePage.WelcomeSection.firstTime.message');
const planMessage = this.$t(`HomePage.WelcomeSection.firstTime.planMessage.${this.userType}`, {
organizationName,
trialLength: this.trialLength
});
return `${firstTimeMessage} ${planMessage}`;
},
baseUrl () {
return this.$store.state.user.base_url;
},
isOrganizationAdmin () {
return this.userType === 'organizationAdmin';
},
isOrganizationUser () {
return this.userType === 'organizationUser';
},
organizationMail () {
const organization = this.$store.state.user.organization;
return organization.admin_email;
},
canCreateDatasets () {
return this.$store.getters['user/canCreateDatasets'];
},
isViewer () {
return this.$store.getters['user/isViewer'];
},
trialLength () {
const trialEndDate = this.$store.state.user.trial_ends_at;
const createdAt = this.$store.state.user.created_at;
return trialEndDate ? differenceInDays(trialEndDate, createdAt) : null;
}
}
};
</script>
<style scoped lang="scss">
@import "new-dashboard/styles/variables";
.welcome-first {
position: relative;
padding: 124px 0;
background: $primary-color;
color: $white;
text-align: center;
&__text {
max-width: 724px;
margin: 16px auto 48px;
}
&__actions {
display: flex;
justify-content: center;
}
.button.button--border {
border: 1px solid $white;
background: none;
color: $white;
text-transform: uppercase;
&:not(:last-child) {
margin-right: 36px;
}
}
}
</style>