Skip to content
Commits on Source (10)
......@@ -41,14 +41,19 @@ context('Groups', () => {
cy.get('.m-groups-save > button').contains('Create').click();
cy.route("POST", "**/api/v1/groups/group/*/banner*").as("postBanner");
cy.wait('@postGroup').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
}).wait('@postBanner').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
// get current groups count of sidebar
cy.get('.m-groupSidebarMarkers__list').children().its('length').then((size) => {
cy.wait('@postGroup').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
}).wait('@postBanner').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.equal('success');
});
//check count changed.
cy.get('.m-groupSidebarMarkers__list').children().should('have.length', size + 1);
});
cy.get('.m-groupInfo__name').contains('test');
cy.get('.m-groupInfo__description').contains('This is a test');
......@@ -73,11 +78,9 @@ context('Groups', () => {
})
it('should be able to toggle conversation and comment on it', () => {
cy.get("m-group--sidebar-markers li:contains('test group')")
.first()
.click();
cy.get('.m-groupSidebarMarkers__list').children().its('length').then((size) => {
cy.get(`m-group--sidebar-markers li:nth-child(${size - 1})`).click();
});
// toggle the conversation
cy.get('.m-groupGrid__right').should('be.visible');
......@@ -98,9 +101,9 @@ context('Groups', () => {
})
it('should post an activity inside the group and record the view when scrolling', () => {
cy.get("m-group--sidebar-markers li:contains('test group')")
.first()
.click();
cy.get('.m-groupSidebarMarkers__list').children().its('length').then((size) => {
cy.get(`m-group--sidebar-markers li:nth-child(${size - 1})`).click();
});
cy.server();
cy.route("POST", "**/api/v2/analytics/views/activity/*").as("view");
......@@ -128,14 +131,18 @@ context('Groups', () => {
});
it('should delete a group', () => {
cy.get('m-group--sidebar-markers li:nth-child(3)').contains('test group').click();
cy.get('.m-groupSidebarMarkers__list').children().its('length').then((size) => {
cy.get(`m-group--sidebar-markers li:nth-child(${size - 1})`).click();
// cleanup
cy.get('minds-groups-settings-button > button').click();
cy.get('minds-groups-settings-button ul.minds-dropdown-menu > li:nth-child(8)').contains('Delete Group').click();
cy.get('minds-groups-settings-button m-modal .mdl-button--raised').contains('Confirm').click();
// cleanup
cy.get('minds-groups-settings-button > button').click();
cy.contains('Delete Group').click();
cy.contains('Confirm').click();
cy.location('pathname').should('eq', '/groups/member');
cy.location('pathname').should('eq', '/groups/member');
cy.get('.m-groupSidebarMarkers__list').children().should('have.length', size - 1);
});
})
})
......@@ -5,36 +5,36 @@ context('Login', () => {
})
it('should login', () => {
cy.get('.m-v2-topbar__Container__LoginWrapper > a').click();
cy.get('.m-v2-topbar__Container__LoginWrapper > a').contains('Login').click();
cy.location('pathname').should('eq', '/login');
// it should have a login form
cy.get('.m-login').should('be.visible');
cy.get('.m-login__wrapper').should('be.visible');
cy.get('minds-form-login .m-login-box .mdl-cell:first-child input').type(Cypress.env().username);
cy.get('minds-form-login .m-login-box .mdl-cell:last-child input').type(Cypress.env().password);
cy.get('minds-form-login .m-btn--login').click();
cy.get('minds-form-login .mf-button--alt').click();
cy.location('pathname')
.should('eq', '/newsfeed/subscriptions');
})
it('should fail to login because of incorrect password', () => {
cy.get('.m-v2-topbar__Container__LoginWrapper > a').click();
cy.get('.m-v2-topbar__Container__LoginWrapper > a').contains('Login').click();
cy.location('pathname').should('eq', '/login');
// it should have a login form
cy.get('.m-login').should('be.visible');
cy.get('.m-login__wrapper').should('be.visible');
cy.get('minds-form-login .m-login-box .mdl-cell:first-child input').type(Cypress.env().username);
cy.get('minds-form-login .m-login-box .mdl-cell:last-child input').type(Cypress.env().password + '1');
cy.get('minds-form-login .m-btn--login').click();
cy.get('minds-form-login .mf-button--alt').click();
cy.wait(500);
......
context('Onboarding', () => {
const email = 'test@minds.com';
const password = 'Passw0rd!';
const name = "Tester";
const description = "I am a tester, with a not so lengthy description";
const welcomeText = "Welcome to Minds!";
const usernameField = 'minds-form-register #username';
const emailField = 'minds-form-register #email';
const passwordField = 'minds-form-register #password';
const password2Field = 'minds-form-register #password2';
const nameField = '#display-name';
const descriptionfield = '#description';
const phoneNumberInput = '#phone';
const countryDropdown = 'm-phone-input--country > div';
const ukOption = 'm-phone-input--country > ul > li:nth-child(2)';
const dialcode = '.m-phone-input--dial-code';
const checkbox = 'minds-form-register label:nth-child(2) .mdl-ripple--center';
const submitButton = 'minds-form-register .mdl-card__actions button';
const nextButton = '.m-channelOnboarding__next';
const submitPhoneButton = 'm-channel--onboarding--rewards > div > div > button';
const loadingSpinner = '.mdl-spinner__gap-patch';
const getTopic = (i) => `m-onboarding--topics > div > ul > li:nth-child(${i}) span`;
before(() => {
cy.clearCookies();
cy.visit('/login');
//type values
cy.get(usernameField).focus().type(Math.random().toString(36).replace('0.', ''));
cy.get(emailField).focus().type(email);
cy.get(passwordField).focus().type(password);
cy.get(password2Field).focus().type(password);
cy.get(checkbox).click();
//submit
cy.get(submitButton).click();
//onboarding modal shown
cy.get('m-onboarding--topics > div > h2:nth-child(1)')
.contains(welcomeText);
});
it('should allow a user to run through onboarding modals', () => {
//select topics
cy.get(getTopic(3)).click().should('have.class', 'selected')
cy.get(getTopic(4)).click().should('have.class', 'selected')
cy.get(getTopic(5)).click().should('have.class', 'selected')
//click
cy.get(nextButton).click();
//TODO: Skipped over for now as subscribed channels is not working on staging environment.
cy.get(nextButton).click();
cy.get(nameField).clear().type(name);
cy.get(descriptionfield).type(description);
cy.get(nextButton).click();
//set dialcode
cy.get(countryDropdown).click();
cy.get(ukOption).click();
cy.get(dialcode).contains('+44');
//type number
cy.get(phoneNumberInput).type('7700000000');
//submit and check loading spinner.
cy.get(submitPhoneButton).click();
cy.get(loadingSpinner).should('be.visible');
cy.get(nextButton).click();
});
});
context('Onboarding', () => {
const remindText = 'remind test text';
before(() => {
cy.getCookie('minds_sess')
.then((sessionCookie) => {
if (sessionCookie === null) {
return cy.login(true);
}
});
cy.visit(`/onboarding`);
// create two test groups
});
beforeEach(() => {
cy.preserveCookies();
});
it('should go through the process of onboarding', () => {
// notice should appear
cy.get('h1.m-onboarding__noticeTitle').contains('Welcome to the Minds Community');
cy.get('h2.m-onboarding__noticeTitle').contains(`@${Cypress.env().username}`);
// should redirect to /hashtags
cy.get('.m-onboarding__form button.mf-button').contains("Let's Get Setup").click();
cy.wait(1000);
// should be in the hashtags step
// should have a Profile Setup title
cy.get('.m-onboarding__form > h2').contains('Profile Setup');
// should have a progressbar, with the hashtags step highlighted
cy.get('.m-onboardingProgressbar__item--selected span').contains('1');
cy.get('.m-onboardingProgressbar__item--selected span').contains('Hashtags');
// should have a description
cy.get('.m-onboarding__form .m-onboarding__description').contains('Select some hashtags that are of interest to you.');
// should have a list of selectable hashtags
cy.get('.m-hashtags__list li.m-hashtagsList__item').contains('Art').click();
cy.get('.m-hashtags__list li.m-hashtagsList__item.m-hashtagsList__item--selected').contains('Art');
cy.get('.m-hashtags__list li.m-hashtagsList__item').contains('Journalism').click();
cy.get('.m-hashtags__list li.m-hashtagsList__item.m-hashtagsList__item--selected');
cy.get('.m-hashtags__list li.m-hashtagsList__item').contains('Music').click();
cy.get('.m-hashtags__list li.m-hashtagsList__item.m-hashtagsList__item--selected');
// should have a continue and a skip button
cy.get('button.mf-button--hollow').contains('Skip');
cy.get('button.mf-button--alt').contains('Continue').click();
// should be in the info step
cy.get('.m-onboardingProgressbar__item--selected span').contains('2');
cy.get('.m-onboardingProgressbar__item--selected span').contains('Info');
// should have a Mobile Phone Number input
cy.get('.m-onboarding__controls .m-onboarding__control label').contains('Mobile Phone Number');
// open country dropdown
cy.get('.m-onboarding__controls .m-phone-input--selected-flag').click();
// click on UK
cy.get('.m-phone-input--country-list li span[data-minds=54]').click();
// Uk should be selected
cy.get('.m-phone-input--selected-flag .m-phone-input--dial-code').contains('+54');
// add the number
cy.get('#phone').type('012345678');
// should have a Location input
cy.get('.m-onboarding__controls > .m-onboarding__control label[data-minds=location]').contains('Location');
cy.get('.m-onboarding__controls > .m-onboarding__control input[data-minds=locationInput]').type('London');
// should have Date of Birth inputs
cy.get('.m-onboarding__controls > .m-onboarding__control label[data-minds=dateOfBirth]').contains('Date of Birth');
// open month selection and pick February
cy.get('.m-onboarding__controls > .m-onboarding__control select[data-minds=monthDropdown]').select('February');
// open day selection and pick 2nd
cy.get('.m-onboarding__controls > .m-onboarding__control select[data-minds=dayDropdown]').select('2');
// open year selection and pick 1991
cy.get('.m-onboarding__controls > .m-onboarding__control select[data-minds=yearDropdown]').select('1991');
// should have a continue and a skip button
cy.get('button.mf-button--hollow').contains('Skip');
cy.get('button.mf-button--alt').contains('Continue').click();
// should be in the Groups step
// should have a groups list
// cy.get('.m-groupList__list').should('exist');
// clicking on a group join button should join the group
// cy.get('.m-groupList__list .m-groupList__item:first-child .m-join__subscribe').contains('add').click();
// // button should change to a check, and clicking on it should leave the group
// cy.get('.m-groupList__list .m-groupList__item:first-child .m-join__subscribed').contains('check').click();
// cy.get('.m-groupList__list .m-groupList__item:first-child .m-join__subscribe i').contains('add');
// should have a continue and a skip button
cy.get('button.mf-button--hollow').contains('Skip');
cy.get('button.mf-button--alt').contains('Continue').click();
// should be in the Channels step
// should have a channels list
// cy.get('.m-channelList__list').should('exist');
// // clicking on a group join button should join the group
// cy.get('.m-channelList__list .m-channelList__item:first-child .m-join__subscribe').contains('add').click();
// // button should change to a check, and clicking on it should leave the channel
// cy.get('.m-channelList__list .m-channelList__item:first-child .m-join__subscribed').contains('check').click();
// cy.get('.m-channelList__list .m-channelList__item:first-child .m-join__subscribe i').contains('add');
// should have a continue and a skip button
cy.get('button.mf-button--hollow').contains('Skip');
cy.get('button.mf-button--alt').contains('Finish').click();
// should be in the newsfeed
cy.location('pathname').should('eq', '/newsfeed/subscriptions');
});
});
......@@ -5,11 +5,6 @@ context('Registration', () => {
const username = generateRandomId();
const password = `${generateRandomId()}0oA!`;
const email = 'test@minds.com';
const noSymbolPass = 'Passw0rd';
const welcomeText = "Welcome to Minds!";
const passwordDontMatch = "Passwords must match.";
const passwordInvalid = " Password must have more than 8 characters. Including uppercase, numbers, special characters (ie. !,#,@), and cannot have spaces. ";
const usernameField = 'minds-form-register #username';
const emailField = 'minds-form-register #email';
......@@ -20,8 +15,8 @@ context('Registration', () => {
beforeEach(() => {
cy.clearCookies();
cy.visit('/login');
cy.location('pathname').should('eq', '/login');
cy.visit('/register');
cy.location('pathname').should('eq', '/register');
cy.server();
cy.route("POST", "**/api/v1/register").as("register");
});
......@@ -39,55 +34,21 @@ context('Registration', () => {
cy.get(usernameField)
.focus()
.type(username);
cy.get(emailField)
.focus()
.type(email);
cy.get(passwordField)
.focus()
.type(password);
cy.wait(500);
cy.get(password2Field)
.focus()
.type(password);
cy.get(checkbox)
.click({force: true});
//submit
cy.get(submitButton)
.click()
.wait('@register').then((xhr) => {
expect(xhr.status).to.equal(200);
});
//onboarding modal shown
cy.contains(welcomeText);
});
it('should display an error if password is invalid', () => {
cy.get(usernameField)
.focus()
.type(generateRandomId());
cy.get(emailField)
.focus()
.type(email);
cy.get(passwordField)
.focus()
.type(noSymbolPass);
cy.wait(500);
cy.get(password2Field)
.focus()
.type(noSymbolPass);
cy.get(checkbox)
.click({force: true});
......@@ -98,37 +59,22 @@ context('Registration', () => {
expect(xhr.status).to.equal(200);
});
cy.scrollTo('top');
cy.contains(passwordInvalid);
cy.wait(500);
cy.location('pathname').should('eq', '/newsfeed/subscriptions');
});
it('should display an error if passwords do not match', () => {
cy.get(usernameField)
.focus()
.type(generateRandomId());
cy.get(emailField)
.focus()
.type(email);
cy.get('minds-form-register #password')
.focus()
.type(password);
cy.wait(500);
cy.get(password2Field)
.focus()
.type(password + '!');
cy.get(checkbox)
.click({force: true});
//submit
cy.get(submitButton).click();
cy.scrollTo('top');
cy.contains(passwordDontMatch);
cy.get('.m-register__error').contains('Passwords must match');
});
})
import 'cypress-file-upload';
/**
* @author Marcelo, Ben and Brian
* @author Marcelo, Ben and Brian
* @create date 2019-08-09 22:54:02
* @modify date 2019-08-09 22:54:02
* @desc Custom commands for access through cy.[cmd]();
*
*
* For more comprehensive examples of custom
* commands please read more here:
* https://on.cypress.io/custom-commands
*
* -- This is a parent command --
* Cypress.Commands.add('login', (email, password) => { ... })
* -- This is a child command --
* Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
* -- This is a dual command --
* Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
* -- This is will overwrite an existing command --
* Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
*/
......@@ -56,7 +56,7 @@ const defaults = {
const loginForm = {
password: 'minds-form-login .m-login-box .mdl-cell:last-child input',
username: 'minds-form-login .m-login-box .mdl-cell:first-child input',
submit: 'minds-form-login .m-btn--login',
submit: 'minds-form-login .mf-button',
}
const poster = {
......@@ -84,7 +84,7 @@ Cypress.Commands.add('login', (canary = false, username, password) => {
cy.get(loginForm.username).focus().type(username);
cy.get(loginForm.password).focus().type(password);
cy.get(loginForm.submit)
.focus()
.click({force: true})
......@@ -104,21 +104,21 @@ Cypress.Commands.add('logout', () => {
/**
* Register a user, be sure to delete the user following this.
*
*
* ! LOG-OUT PRIOR TO CALLING !
*
*
* @param { string } username - The username. Note that the requested username will NOT be freed up upon deletion
* @param { string } password - The users password.
* @returns void
*/
Cypress.Commands.add('newUser', (username = '', password = '') => {
cy.visit('/login')
cy.visit('/register')
.location('pathname')
.should('eq', `/login`);
.should('eq', `/register`);
cy.server();
cy.route("POST", '**/api/v1/register').as('registerPOST');
cy.get(registerForm.username).focus().type(username);
cy.get(registerForm.email).focus().type(defaults.email);
cy.get(registerForm.password).focus().type(password);
......@@ -137,7 +137,7 @@ Cypress.Commands.add('newUser', (username = '', password = '') => {
//onboarding modal shown.
cy.get(onboarding.welcomeTextContainer)
.contains(onboarding.welcomeText);
//skip onboarding.
cy.get(onboarding.nextButton).click()
cy.get(onboarding.nextButton).click()
......@@ -151,14 +151,14 @@ Cypress.Commands.add('preserveCookies', () => {
/**
* Deletes a user. Use carefully on sandbox or you may lose your favorite test account.
*
*
* ! LOG-IN PRIOR TO CALLING !
*
*
* @param { string } username - The username. TODO: when both params provided log the user in too
* @param { string } password - The password.
* @returns void
*/
Cypress.Commands.add('deleteUser', (username, password) => {
Cypress.Commands.add('deleteUser', (username, password) => {
cy.server();
cy.route("POST", '**/api/v2/settings/password/validate').as('validatePost');
cy.route("POST", '**/api/v2/settings/delete').as('deletePOST');
......@@ -170,7 +170,7 @@ Cypress.Commands.add('deleteUser', (username, password) => {
cy.get(settings.deleteAccountButton).click({ force: true });
cy.get('#password').focus().type(password);
cy.get(settings.deleteSubmitButton).click({ force: true })
cy.get(settings.deleteSubmitButton).click({ force: true })
.wait('@validatePost').then((xhr) => {
expect(xhr.status).to.equal(200);
expect(xhr.response.body.status).to.deep.equal("success");
......@@ -193,9 +193,9 @@ Cypress.Commands.add('uploadFile', (selector, fileName, type = '') => {
cy.fixture(fileName).then((content) => {
cy.log("Content", fileName);
cy.get(selector).upload({
fileContent: content,
fileName: fileName,
mimeType: type
fileContent: content,
fileName: fileName,
mimeType: type
});
});
});
......@@ -218,7 +218,7 @@ Cypress.Commands.add('post', (message) => {
/**
* Sets the feature flag cookie.
* @param { Object } flags - JSON object containing flags to turn on
* @param { Object } flags - JSON object containing flags to turn on
* e.g. { dark mode:false, es-feeds: true }
* @returns void
*/
......
......@@ -1980,11 +1980,6 @@
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
"dev": true
},
"@types/video.js": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.3.tgz",
"integrity": "sha512-yAb46+4A0dKFxOQRVLoLyfC/S/BmHLE10MxPXt/t88+7R4GWLHosHelVtYpKBRykjptdkqfQXNRXoQzDeKm6MA=="
},
"@types/webpack-sources": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz",
......@@ -12596,6 +12591,13 @@
"requires": {
"moment": "2.10.6",
"rome": "git+https://github.com/joews/rome.git#19f5d3031a922c29c52b9038b2832a827e5e99d6"
},
"dependencies": {
"moment": {
"version": "2.10.6",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz",
"integrity": "sha1-bLIZZ8ecunsMpeZmRPFzZis++nc="
}
}
},
"material-design-icons": {
......@@ -12968,9 +12970,9 @@
}
},
"moment": {
"version": "2.10.6",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz",
"integrity": "sha1-bLIZZ8ecunsMpeZmRPFzZis++nc="
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"monotone-convex-hull-2d": {
"version": "1.0.1",
......
......@@ -113,7 +113,10 @@ export class Minds {
this.minds.user.language,
this.minds.language
);
window.location.reload(true);
setTimeout(() => {
window.location.reload(true);
});
}
}
});
......
......@@ -52,7 +52,6 @@ import { BanModule } from './modules/ban/ban.module';
import { BlogModule } from './modules/blogs/blog.module';
import { SearchModule } from './modules/search/search.module';
import { MessengerModule } from './modules/messenger/messenger.module';
import { HomepageModule } from './modules/homepage/homepage.module';
import { NewsfeedModule } from './modules/newsfeed/newsfeed.module';
import { MediaModule } from './modules/media/media.module';
import { AuthModule } from './modules/auth/auth.module';
......@@ -73,6 +72,8 @@ import { ChannelContainerModule } from './modules/channel-container/channel-cont
import { UpgradesModule } from './modules/upgrades/upgrades.module';
import * as Sentry from '@sentry/browser';
import { HomepageModule } from './modules/homepage/homepage.module';
import { OnboardingV2Module } from './modules/onboarding-v2/onboarding.module';
Sentry.init({
dsn: 'https://3f786f8407e042db9053434a3ab527a2@sentry.io/1538008', // TODO: do not hardcard
......@@ -127,6 +128,7 @@ export class SentryErrorHandler implements ErrorHandler {
PaymentsModule,
MindsFormsModule,
OnboardingModule,
OnboardingV2Module,
NotificationModule,
GroupsModule,
BlogModule,
......
......@@ -127,6 +127,12 @@ import { FormDescriptorComponent } from './components/form-descriptor/form-descr
import { FormToastComponent } from './components/form-toast/form-toast.component';
import { SsoService } from './services/sso.service';
import { PagesService } from './services/pages.service';
<<<<<<< HEAD
import { V2TopbarService } from './layout/v2-topbar/v2-topbar.service';
import { DateDropdownsComponent } from './components/date-dropdowns/date-dropdowns.component';
import { SidebarMarkersService } from './layout/sidebar/markers.service';
=======
>>>>>>> 0eb70a775f10cf0c5b9d8f2b45bde7a237f98372
import { EmailConfirmationComponent } from './components/email-confirmation/email-confirmation.component';
PlotlyModule.plotlyjs = PlotlyJS;
......@@ -252,6 +258,7 @@ const routes: Routes = [
FormToastComponent,
ShadowboxSubmitButtonComponent,
EmailConfirmationComponent,
DateDropdownsComponent,
],
exports: [
MINDS_PIPES,
......@@ -352,6 +359,7 @@ const routes: Routes = [
FormToastComponent,
ShadowboxSubmitButtonComponent,
EmailConfirmationComponent,
DateDropdownsComponent,
],
providers: [
SiteService,
......@@ -419,6 +427,14 @@ const routes: Routes = [
useFactory: router => new RouterHistoryService(router),
deps: [Router],
},
{
provide: V2TopbarService,
useFactory: V2TopbarService._,
},
{
provide: SidebarMarkersService,
useFactory: SidebarMarkersService._,
},
],
entryComponents: [
NotificationsToasterComponent,
......
......@@ -130,6 +130,10 @@ export class MindsAvatar {
* @returns true if the object guid matches the currently logged in user guid
*/
isOwnerAvatar(): boolean {
return this.minds.user && this.object.guid === this.minds.user.guid;
return (
this.minds.user &&
this.object &&
this.object.guid === this.minds.user.guid
);
}
}
m-date__dropdowns {
display: flex;
justify-content: space-between;
select {
display: inline-block;
background-color: #fff;
box-sizing: border-box;
margin: 0 10px 0 0;
padding: 8px 10px;
height: 36px;
min-width: 80px;
max-width: 90px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
font-size: 16px;
line-height: 21px;
border-radius: 2px;
@include m-theme() {
color: themed($m-grey-800);
background-color: themed($m-white);
border: 1px solid #e2e2e2;
}
// month
&:nth-child(1) {
min-width: 120px;
}
// day
&:nth-child(2) {
min-width: 59px;
}
// year
&:nth-child(3) {
min-width: 77px;
}
}
}
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
@Component({
selector: 'm-date__dropdowns',
template: `
<select
data-minds="monthDropdown"
[ngModel]="selectedMonth"
(ngModelChange)="selectMonth($event)"
>
<option *ngFor="let month of monthNames">{{ month }}</option>
</select>
<select
data-minds="dayDropdown"
[ngModel]="selectedDay"
(ngModelChange)="selectDay($event)"
>
<option *ngFor="let day of days">{{ day }}</option>
</select>
<select
data-minds="yearDropdown"
[ngModel]="selectedYear"
(ngModelChange)="selectYear($event)"
>
<option *ngFor="let year of years">{{ year }}</option>
</select>
`,
})
export class DateDropdownsComponent implements OnInit {
@Output() selectedDateChange: EventEmitter<string> = new EventEmitter<
string
>();
monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
days = [1];
years = [];
selectedMonth = 'January';
selectedDay = '1';
selectedYear = new Date().getFullYear();
constructor() {}
ngOnInit() {
this.years = this.range(100, this.selectedYear, false);
this.selectedYear = this.years[0];
this.selectMonth('January');
}
selectMonth(month: string) {
this.selectedMonth = month;
this.populateDays(
this.getDaysInMonth(this.getMonthNumber(month), this.selectedYear)
);
this.selectedDateChange.emit(this.buildDate());
}
selectDay(day: string) {
this.selectedDay = day;
this.selectedDateChange.emit(this.buildDate());
}
selectYear(year) {
this.selectedYear = year;
this.populateDays(
this.getDaysInMonth(this.getMonthNumber(this.selectedMonth), year)
);
this.selectedDateChange.emit(this.buildDate());
}
buildDate() {
let date: string = '';
if (this.selectedMonth !== '') {
if (this.selectedYear) {
date = `${this.pad(this.selectedYear, 4)}-`;
}
const monthIndex = this.monthNames.findIndex(
item => item === this.selectedMonth
);
date += `${this.pad(monthIndex + 1, 2)}`;
if (this.selectedDay) {
date += `-${this.pad(this.selectedDay, 2)}`;
}
}
return date;
}
private populateDays(maxDays: number) {
this.days = this.range(maxDays, 1);
}
private getMonthNumber(month: string): number {
return this.monthNames.indexOf(month);
}
private getDaysInMonth(month, year): number {
// let date = new Date(Date.UTC(year, month, 1));
const date = new Date(year, month, 1);
let day = 0;
while (date.getMonth() === month) {
day = date.getDate();
date.setDate(date.getDate() + 1);
}
return day;
}
private range(size, startAt = 0, grow = true): Array<number> {
return Array.from(Array(size).keys()).map(i => {
if (grow) {
return i + startAt;
} else {
return startAt - i;
}
});
}
private pad(val: any, pad: number = 0) {
if (!pad) {
return val;
}
return (Array(pad + 1).join('0') + val).slice(-pad);
}
}
......@@ -8,8 +8,9 @@
<h4 class="m-marketingFooter__sloganText" i18n>
Take back control of your social media
</h4>
<div class="m-marketingFooter__text">&copy; {{ year }} Minds, Inc.</div>
<div class="m-marketingFooter__text" *ngIf="!isMobile">
&copy; {{ year }} Minds, Inc.
</div>
</div>
<div
......@@ -201,6 +202,9 @@
<div
class="m-grid__column-12 m-grid__column-12--mobile m-marketingFooter__column"
>
<div class="m-marketingFooter__text" *ngIf="isMobile">
&copy; {{ year }} Minds, Inc.
</div>
<ul class="m-marketingFooter__inlineList m-marketingFooter__legalLinks">
<li>
<a routerLink="/p/terms" i18n>
......
......@@ -40,6 +40,14 @@ m-marketing__footer {
}
.m-marketingFooter__column {
@media screen and(max-width: $m-grid-max-mobile) {
@for $i from 1 through 5 {
&:nth-child(#{$i}) {
grid-row: $i;
}
}
}
@media screen and (max-width: $m-grid-min-vp) {
margin-bottom: 32px;
......@@ -53,9 +61,7 @@ m-marketing__footer {
width: 60%;
margin: 0 auto;
@media screen and (max-width: $m-grid-min-vp) {
width: 60%;
grid-row: 999;
@media screen and (max-width: $m-grid-max-mobile) {
margin: 32px 0 0;
}
}
......@@ -75,7 +81,12 @@ m-marketing__footer {
}
&.m-marketingFooter__sloganText {
font-weight: 400;
margin: 0 0 21px;
@include m-theme() {
color: themed($m-grey-600);
}
}
}
......@@ -115,15 +126,6 @@ m-marketing__footer {
color: themed($m-grey-300);
}
@media screen and (max-width: $m-grid-min-vp) {
display: inline-block;
margin-right: 1em;
&:last-child {
margin-right: 0;
}
}
a {
color: inherit;
font-weight: normal;
......@@ -149,7 +151,7 @@ m-marketing__footer {
text-align: right;
padding-right: 92px;
@media screen and (max-width: $m-grid-min-vp) {
@media screen and (max-width: $m-grid-max-mobile) {
text-align: inherit;
padding-right: initial;
}
......
import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
HostListener,
OnInit,
} from '@angular/core';
@Component({
selector: 'm-marketing__footer',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'footer.component.html',
})
export class MarketingFooterComponent {
export class MarketingFooterComponent implements OnInit {
readonly year: number = new Date().getFullYear();
readonly cdnAssetsUrl: string = window.Minds.cdn_assets_url;
isMobile: boolean;
constructor(protected cd: ChangeDetectorRef) {}
ngOnInit() {
this.onResize();
}
@HostListener('window:resize')
onResize() {
this.isMobile = window.innerWidth <= 480;
this.detectChanges();
}
detectChanges() {
this.cd.markForCheck();
this.cd.detectChanges();
}
}
......@@ -3,6 +3,10 @@
m-marketing {
display: block;
font-family: Roboto, sans-serif;
overflow-x: hidden;
min-width: 320px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
@include m-theme() {
background: themed($m-white);
......
......@@ -2,23 +2,40 @@ import {
ChangeDetectionStrategy,
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { MindsTitle } from '../../../services/ux/title';
import { V2TopbarService } from '../../layout/v2-topbar/v2-topbar.service';
@Component({
selector: 'm-marketing',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'marketing.component.html',
})
export class MarketingComponent implements OnInit {
export class MarketingComponent implements OnInit, OnDestroy {
@Input() pageTitle: string = '';
@Input() showBottombar: boolean = true;
@Input() forceBackground: boolean = true;
constructor(protected title: MindsTitle) {}
constructor(
protected title: MindsTitle,
private topbarService: V2TopbarService
) {}
ngOnInit() {
if (this.pageTitle) {
this.title.setTitle(this.pageTitle);
}
this.topbarService.toggleMarketingPages(
true,
this.showBottombar,
this.forceBackground
);
}
ngOnDestroy() {
this.topbarService.toggleMarketingPages(false);
}
}
......@@ -119,6 +119,13 @@
}
}
a.m-marketing__link {
text-decoration: none;
@include m-theme() {
color: themed($m-blue);
}
}
.m-marketing__links {
@media screen and (max-width: $m-grid-min-vp) {
text-align: center;
......@@ -169,4 +176,110 @@
}
}
}
span.m-marketing__imageUX {
span.m-marketing__imageTick {
border-radius: 50%;
background-color: #4fc3a9;
color: white;
width: 63px;
height: 63px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 39px -4px rgba(0, 0, 0, 0.5);
z-index: 3;
@media screen and (max-width: $max-mobile) {
width: 10vw;
height: 10vw;
font-size: 5vw;
}
}
.m-marketing__imageTick--left {
position: absolute;
bottom: 62px;
left: -21px;
@media screen and(min-width: $max-mobile) and (max-width: $m-grid-min-vp) {
bottom: -23%;
left: 8.5%;
}
@media screen and (max-width: $max-mobile) {
//bottom: -116px;
//left: 2px;
bottom: -27%;
left: 2.5%;
}
}
.m-marketing__imageTick--right {
position: absolute;
bottom: 8px;
left: -45px;
@media screen and(min-width: $max-mobile) and (max-width: $m-grid-min-vp) {
bottom: 0;
right: 0;
left: auto;
}
@media screen and (max-width: $max-mobile) {
//bottom: -116px;
//left: 2px;
bottom: -27%;
left: 2.5%;
}
}
img {
box-shadow: 0 0 39px -4px rgba(0, 0, 0, 0.5);
}
}
.m-marketing__quotation {
display: flex;
flex-direction: column;
align-items: flex-end;
margin: 0 auto;
@media screen and(min-width: $m-grid-min-vp) {
width: 730px;
}
h3 {
font-size: 28px;
font-weight: bold;
line-height: 37px;
margin-bottom: 0;
}
h4 {
font-size: 14px;
line-height: 19px;
margin: 0;
@include m-theme() {
color: themed($m-grey-300);
}
}
}
.mf-button.mf-button--alt.mf-button--gradient {
background: #5dbac0; /* Old Browsers */
background: linear-gradient(
45deg,
#4eb69f 0%,
#4fc3aa 49%,
#4eb69f 49%,
#4fc3aa 100%
);
}
}