Skip to content

Commit

Permalink
[fix] Foursquare storage provider improvements (#2800)
Browse files Browse the repository at this point in the history
- Change default height of the auth popup to show "Continue with Google" and bottom links.
- Show an info helper that not all FSQ maps are expected to show up in Load From Storage modal.
- fix constant reloading of map from link mode
- fix jest tests

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>
  • Loading branch information
igorDykhta authored Dec 4, 2024
1 parent 95448ac commit 6223be9
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 42 deletions.
14 changes: 11 additions & 3 deletions examples/demo-app/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project

import React, {useCallback, useEffect, useMemo, useState} from 'react';
import React, {useCallback, useEffect, useRef, useMemo, useState} from 'react';
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import styled, {ThemeProvider} from 'styled-components';
import window from 'global/window';
import {connect, useDispatch} from 'react-redux';
import cloneDeep from 'lodash.clonedeep';
import isEqual from 'lodash.isequal';

import {ScreenshotWrapper} from 'react-ai-assist';
import {
Expand Down Expand Up @@ -103,19 +104,26 @@ const App = props => {
const {params: {id, provider} = {}, location: {query = {}} = {}} = props;
const dispatch = useDispatch();

const prevQueryRef = useRef<number>(null);

useEffect(() => {
// if we pass an id as part of the url
// we ry to fetch along map configurations

// we try to fetch along map configurations
const cloudProvider = CLOUD_PROVIDERS.find(c => c.name === provider);
if (cloudProvider) {
// Prevent constant reloading after change of the location
if (isEqual(prevQueryRef.current, {provider, id, query})) {
return;
}

dispatch(
loadCloudMap({
loadParams: query,
provider: cloudProvider,
onSuccess: onLoadCloudMapSuccess
})
);
prevQueryRef.current = {provider, id, query};
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {Auth0Client} from '@auth0/auth0-spa-js';

const NAME = 'foursquare';
const DISPLAY_NAME = 'Foursquare';
const STORAGE_MESSAGE = 'modal.loadStorageMap.foursquareStorageMessage';

const APP_NAME = 'Kepler.gl';

const FOURSQUARE_PRIVATE_STORAGE_ENABLED = true;
Expand Down Expand Up @@ -35,6 +37,22 @@ function convertFSQModelToMapItem(model, baseApi) {
};
}

/**
* Custom Auth0 popup window to change window height to fit FSQ auth window.
*/
export const openPopup = url => {
const width = 400;
const height = 765;
const left = window.screenX + (window.innerWidth - width) / 2;
const top = window.screenY + (window.innerHeight - height) / 2;

return window.open(
url,
'auth0:authorize:popup',
`left=${left},top=${top},width=${width},height=${height},resizable,scrollbars=yes,status=1`
);
};

function extractMapFromFSQResponse(response) {
const {
latestState: {data}
Expand All @@ -44,7 +62,7 @@ function extractMapFromFSQResponse(response) {

export default class FoursquareProvider extends Provider {
constructor({clientId, authDomain, apiURL, userMapsURL}) {
super({name: NAME, displayName: DISPLAY_NAME, icon: FSQIcon});
super({name: NAME, displayName: DISPLAY_NAME, storageMessage: STORAGE_MESSAGE, icon: FSQIcon});
this.icon = FSQIcon;
this.appName = APP_NAME;
this.apiURL = apiURL;
Expand Down Expand Up @@ -74,7 +92,7 @@ export default class FoursquareProvider extends Provider {
}

async login() {
return this._auth0.loginWithPopup();
return this._auth0.loginWithPopup(undefined, {popup: openPopup()});
}

async logout() {
Expand Down Expand Up @@ -139,9 +157,19 @@ export default class FoursquareProvider extends Provider {
}

async downloadMap(loadParams) {
const {id} = loadParams;
let {id, path} = loadParams;
if (!id) {
// try to get map id from foursquare map path
if (typeof path === 'string') {
const pathId = /((\w{4,12}-?)){5}/.exec(path)[0];
if (pathId) {
id = pathId;
}
}
}

if (!id) {
return Promise.reject('No Map is was provider as part of loadParams');
return Promise.reject('No Map id was provider as part of loadParams');
}
const headers = await this.getHeaders();

Expand All @@ -160,7 +188,7 @@ export default class FoursquareProvider extends Provider {

getMapUrl(loadParams) {
const {id} = loadParams;
return `${this.apiURL}/v1/maps/${id}`;
return id ? `${this.apiURL}/v1/maps/${id}` : null;
}

getManagementUrl() {
Expand Down
3 changes: 3 additions & 0 deletions src/cloud-providers/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export type Thumbnail = {
export type ProviderProps = {
name?: string;
displayName?: string;
storageMessage?: string;
icon?: ComponentType<IconProps>;
thumbnail?: Thumbnail;
};
Expand Down Expand Up @@ -72,13 +73,15 @@ export const FILE_CONFLICT_MSG = 'file_conflict';
export default class Provider {
name: string;
displayName: string;
storageMessage?: string;
icon: ComponentType<IconProps>;
thumbnail: Thumbnail;
isNew = false;

constructor(props: ProviderProps) {
this.name = props.name || NAME;
this.displayName = props.displayName || DISPLAY_NAME;
this.storageMessage = props.storageMessage;
this.icon = props.icon || ICON;
this.thumbnail = props.thumbnail || THUMBNAIL;
}
Expand Down
77 changes: 47 additions & 30 deletions src/components/src/modals/cloud-components/cloud-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import React, {useMemo} from 'react';
import {Button} from '../../common/styled-components';
import {ArrowLeft} from '../../common/icons';
import InfoHelperFactory from '../../common/info-helper';
import {FormattedMessage} from '@kepler.gl/localization';
import styled from 'styled-components';
import {dataTestIds} from '@kepler.gl/constants';
Expand Down Expand Up @@ -32,6 +33,7 @@ const StyledBackBtn = styled.a`
const LINK_STYLE = {textDecoration: 'underline'};

const Title = styled.span`
display: flex;
font-size: 14px;
line-height: 16px;
font-weight: 500;
Expand All @@ -47,33 +49,48 @@ type CloudHeaderProps = {
onBack: () => void;
};

export const CloudHeader: React.FC<CloudHeaderProps> = ({provider, onBack}) => {
const managementUrl = useMemo(() => provider.getManagementUrl(), [provider]);
return (
<div data-testid={dataTestIds.cloudHeader}>
<StyledStorageHeader>
<StyledBackBtn>
<Button link onClick={onBack}>
<ArrowLeft height="14px" />
<FormattedMessage id={'modal.loadStorageMap.back'} />
</Button>
</StyledBackBtn>
{managementUrl && (
<a
key={1}
href={managementUrl}
target="_blank"
rel="noopener noreferrer"
style={LINK_STYLE}
>
{provider.displayName}
</a>
)}
</StyledStorageHeader>
<Title>
<span>{provider.displayName}</span>
<FormattedMessage id={'modal.loadStorageMap.storageMaps'} />
</Title>
</div>
);
};
CloudHeaderFactory.deps = [InfoHelperFactory];

function CloudHeaderFactory(InfoHelper: ReturnType<typeof InfoHelperFactory>) {
const CloudHeader: React.FC<CloudHeaderProps> = ({provider, onBack}) => {
const managementUrl = useMemo(() => provider.getManagementUrl(), [provider]);
return (
<div data-testid={dataTestIds.cloudHeader}>
<StyledStorageHeader>
<StyledBackBtn>
<Button link onClick={onBack}>
<ArrowLeft height="14px" />
<FormattedMessage id={'modal.loadStorageMap.back'} />
</Button>
</StyledBackBtn>
{managementUrl && (
<a
key={1}
href={managementUrl}
target="_blank"
rel="noopener noreferrer"
style={LINK_STYLE}
>
{provider.displayName}
</a>
)}
</StyledStorageHeader>
<Title>
<div>
<span>{provider.displayName}</span>{' '}
<FormattedMessage id={'modal.loadStorageMap.storageMaps'} />
</div>
{provider.storageMessage ? (
<InfoHelper
id={`cloud-provider-storageMessage`}
description={provider.storageMessage}
/>
) : null}
</Title>
</div>
);
};
return CloudHeader;
}

export default CloudHeaderFactory;
6 changes: 5 additions & 1 deletion src/components/src/modals/load-storage-map.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
// @ts-nocheck
import React from 'react';
import {fireEvent, waitFor} from '@testing-library/react';
import InfoHelperFactory from '../common/info-helper';
import CloudHeaderFactory from './cloud-components/cloud-header';
import LoadStorageMapFactory from './load-storage-map';
import {renderWithTheme} from 'test/helpers/component-jest-utils';
import {useCloudListProvider} from '../hooks/use-cloud-list-provider';
import {dataTestIds} from '@kepler.gl/constants';

const LoadStorageMap = LoadStorageMapFactory();
const InfoHelper = InfoHelperFactory();
const CloudHeader = CloudHeaderFactory(InfoHelper);
const LoadStorageMap = LoadStorageMapFactory(CloudHeader);

const DEFAULT_MAPS = [
{
Expand Down
6 changes: 4 additions & 2 deletions src/components/src/modals/load-storage-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
// Copyright contributors to the kepler.gl project

import React, {useCallback, useState, useEffect} from 'react';
import {CloudHeader} from './cloud-components/cloud-header';
import CloudHeaderFactory from './cloud-components/cloud-header';
import {CloudMaps} from './cloud-components/cloud-maps';
import {useCloudListProvider} from '../hooks/use-cloud-list-provider';
import {ProviderSelect} from './cloud-components/provider-select';
import {FlexColContainer} from '../common/flex-container';
import {Provider, MapListItem} from '@kepler.gl/cloud-providers';

function LoadStorageMapFactory() {
LoadStorageMapFactory.deps = [CloudHeaderFactory];

function LoadStorageMapFactory(CloudHeader: ReturnType<typeof CloudHeaderFactory>) {
const LoadStorageMap = ({onLoadCloudMap}) => {
const {provider: currentProvider, setProvider, cloudProviders} = useCloudListProvider();
const [isLoading, setIsLoading] = useState(false);
Expand Down
4 changes: 3 additions & 1 deletion src/localization/src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,9 @@ ${'```'}
back: 'Back',
goToPage: 'Go to your Kepler.gl {displayName} page',
storageMaps: 'Storage / Maps',
noSavedMaps: 'No saved maps yet'
noSavedMaps: 'No saved maps yet',
foursquareStorageMessage:
'Only maps saved with Kepler.gl > Save > Foursquare Storage option are shown here'
}
},
header: {
Expand Down

0 comments on commit 6223be9

Please sign in to comment.