mirror of
https://github.com/chinchang/web-maker.git
synced 2025-07-09 16:06:21 +02:00
add share modal
This commit is contained in:
@ -23,7 +23,7 @@ export function MainHeader(props) {
|
|||||||
id="titleInput"
|
id="titleInput"
|
||||||
title="Click to edit"
|
title="Click to edit"
|
||||||
class="item-title-input"
|
class="item-title-input"
|
||||||
value={props.title}
|
value={props.currentItem.title}
|
||||||
onBlur={props.titleInputBlurHandler}
|
onBlur={props.titleInputBlurHandler}
|
||||||
/>
|
/>
|
||||||
<div class="main-header__btn-wrap flex flex-v-center">
|
<div class="main-header__btn-wrap flex flex-v-center">
|
||||||
@ -73,6 +73,24 @@ export function MainHeader(props) {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="btn btn--dark hint--rounded hint--bottom-left"
|
||||||
|
aria-label={i18n._(t`Start a new creation`)}
|
||||||
|
data-testid="newButton"
|
||||||
|
onClick={props.shareBtnHandler}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill={props.currentItem.isPublic ? 'green' : 'currentColor'}
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M18 16.08C17.24 16.08 16.56 16.38 16.04 16.85L8.91 12.7C8.96 12.47 9 12.24 9 12S8.96 11.53 8.91 11.3L15.96 7.19C16.5 7.69 17.21 8 18 8C19.66 8 21 6.66 21 5S19.66 2 18 2 15 3.34 15 5C15 5.24 15.04 5.47 15.09 5.7L8.04 9.81C7.5 9.31 6.79 9 6 9C4.34 9 3 10.34 3 12S4.34 15 6 15C6.79 15 7.5 14.69 8.04 14.19L15.16 18.34C15.11 18.55 15.08 18.77 15.08 19C15.08 20.61 16.39 21.91 18 21.91S20.92 20.61 20.92 19C20.92 17.39 19.61 16.08 18 16.08M18 4C18.55 4 19 4.45 19 5S18.55 6 18 6 17 5.55 17 5 17.45 4 18 4M6 13C5.45 13 5 12.55 5 12S5.45 11 6 11 7 11.45 7 12 6.55 13 6 13M18 20C17.45 20 17 19.55 17 19S17.45 18 18 18 19 18.45 19 19 18.55 20 18 20Z" />
|
||||||
|
</svg>
|
||||||
|
<Trans>Share</Trans>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="btn btn--dark hint--rounded hint--bottom-left"
|
class="btn btn--dark hint--rounded hint--bottom-left"
|
||||||
aria-label={i18n._(t`Start a new creation`)}
|
aria-label={i18n._(t`Start a new creation`)}
|
||||||
|
71
src/components/Share.jsx
Normal file
71
src/components/Share.jsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { useEffect, useState } from 'preact/hooks';
|
||||||
|
import { ProBadge } from './ProBadge';
|
||||||
|
import { HStack, Stack, VStack } from './Stack';
|
||||||
|
import Switch from './Switch';
|
||||||
|
import { itemService } from '../itemService';
|
||||||
|
import { alertsService } from '../notifications';
|
||||||
|
|
||||||
|
const FREE_PUBLIC_ITEM_COUNT = 1;
|
||||||
|
|
||||||
|
export function Share({ user, item, onVisibilityChange }) {
|
||||||
|
const [publicItemCount, setPublicItemCount] = useState(0);
|
||||||
|
useEffect(() => {
|
||||||
|
window.db.getPublicItemCount(user.uid).then(c => {
|
||||||
|
setPublicItemCount(c);
|
||||||
|
console.log(c);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [val, setVal] = useState(item.isPublic);
|
||||||
|
const onChange = async e => {
|
||||||
|
const newVal = e.target.checked;
|
||||||
|
setVal(newVal);
|
||||||
|
if (newVal) {
|
||||||
|
const token = await window.user.getIdToken();
|
||||||
|
const res = await fetch(
|
||||||
|
`http://127.0.0.1:5001/web-maker-app/us-central1/toggleVisibility?token=${token}&itemId=${item.id}`
|
||||||
|
);
|
||||||
|
console.log(res.status);
|
||||||
|
|
||||||
|
if (res.status >= 200 && res.status < 400) {
|
||||||
|
setPublicItemCount(publicItemCount + 1);
|
||||||
|
onVisibilityChange(true);
|
||||||
|
alertsService.add('Visiblity set to public');
|
||||||
|
} else {
|
||||||
|
alertsService.add('Could not set visiblity to public');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
itemService.setItem(item.id, { isPublic: false });
|
||||||
|
setPublicItemCount(publicItemCount - 1);
|
||||||
|
onVisibilityChange(false);
|
||||||
|
alertsService.add('Visiblity set to private');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<VStack gap={4} align="stretch">
|
||||||
|
<VStack gap={1} align="stretch">
|
||||||
|
<Switch checked={val} onChange={onChange}>
|
||||||
|
Go public?
|
||||||
|
</Switch>
|
||||||
|
{item.isPublic && (
|
||||||
|
<p>
|
||||||
|
Public at{' '}
|
||||||
|
<a href={`https://webmaker.app/create/${item.id}`} target="_blank">
|
||||||
|
https://webmaker.app/create/{item.id}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
|
||||||
|
<VStack gap={1} align="stretch">
|
||||||
|
<p>
|
||||||
|
You have {FREE_PUBLIC_ITEM_COUNT - publicItemCount}/
|
||||||
|
{FREE_PUBLIC_ITEM_COUNT} public creations left.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
For unlimited public creations, upgrade to <ProBadge />
|
||||||
|
</p>
|
||||||
|
</VStack>
|
||||||
|
</VStack>
|
||||||
|
);
|
||||||
|
}
|
@ -70,6 +70,7 @@ import { commandPaletteService } from '../commandPaletteService';
|
|||||||
import { I18nProvider } from '@lingui/react';
|
import { I18nProvider } from '@lingui/react';
|
||||||
import { Assets } from './Assets.jsx';
|
import { Assets } from './Assets.jsx';
|
||||||
import { LocalStorageKeys } from '../constants.js';
|
import { LocalStorageKeys } from '../constants.js';
|
||||||
|
import { Share } from './Share.jsx';
|
||||||
|
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
require('preact/debug');
|
require('preact/debug');
|
||||||
@ -119,7 +120,8 @@ export default class App extends Component {
|
|||||||
isJs13KModalOpen: false,
|
isJs13KModalOpen: false,
|
||||||
isCreateNewModalOpen: false,
|
isCreateNewModalOpen: false,
|
||||||
isCommandPaletteOpen: false,
|
isCommandPaletteOpen: false,
|
||||||
isAssetsOpen: false
|
isAssetsOpen: false,
|
||||||
|
isShareModalOpen: false
|
||||||
};
|
};
|
||||||
this.state = {
|
this.state = {
|
||||||
isSavedItemPaneOpen: false,
|
isSavedItemPaneOpen: false,
|
||||||
@ -169,14 +171,14 @@ export default class App extends Component {
|
|||||||
window.user = savedUser;
|
window.user = savedUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
firebase.auth().onAuthStateChanged(user => {
|
firebase.auth().onAuthStateChanged(authUser => {
|
||||||
this.setState({ isLoginModalOpen: false });
|
this.setState({ isLoginModalOpen: false });
|
||||||
if (user) {
|
if (authUser) {
|
||||||
log('You are -> ', user);
|
log('You are -> ', authUser);
|
||||||
alertsService.add('You are now logged in!');
|
alertsService.add('You are now logged in!');
|
||||||
this.setState({ user });
|
this.setState({ user: authUser });
|
||||||
window.user = user;
|
window.user = authUser;
|
||||||
window.localStorage.setItem('user', user);
|
window.localStorage.setItem('user', authUser);
|
||||||
if (!window.localStorage[LocalStorageKeys.ASKED_TO_IMPORT_CREATIONS]) {
|
if (!window.localStorage[LocalStorageKeys.ASKED_TO_IMPORT_CREATIONS]) {
|
||||||
this.fetchItems(false, true).then(items => {
|
this.fetchItems(false, true).then(items => {
|
||||||
if (!items.length) {
|
if (!items.length) {
|
||||||
@ -190,11 +192,14 @@ export default class App extends Component {
|
|||||||
trackEvent('ui', 'askToImportModalSeen');
|
trackEvent('ui', 'askToImportModalSeen');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.db.getUser(user.uid).then(customUser => {
|
// storing actual firebase user object for accessing functions like updateProfile
|
||||||
|
// window.user.firebaseUser = authUser
|
||||||
|
|
||||||
|
window.db.getUser(authUser.uid).then(customUser => {
|
||||||
if (customUser) {
|
if (customUser) {
|
||||||
const prefs = { ...this.state.prefs };
|
const prefs = { ...this.state.prefs };
|
||||||
Object.assign(prefs, user.settings);
|
Object.assign(prefs, authUser.settings);
|
||||||
const newUser = { ...user, isPro: false, ...customUser };
|
const newUser = { ...authUser, isPro: false, ...customUser };
|
||||||
window.localStorage.setItem('user', newUser);
|
window.localStorage.setItem('user', newUser);
|
||||||
this.setState({ user: newUser, prefs }, this.updateSetting);
|
this.setState({ user: newUser, prefs }, this.updateSetting);
|
||||||
}
|
}
|
||||||
@ -1106,6 +1111,10 @@ export default class App extends Component {
|
|||||||
trackEvent('ui', 'openBtnClick');
|
trackEvent('ui', 'openBtnClick');
|
||||||
this.openSavedItemsPane();
|
this.openSavedItemsPane();
|
||||||
}
|
}
|
||||||
|
shareBtnClickHandler() {
|
||||||
|
trackEvent('ui', 'shareBtnClick');
|
||||||
|
this.setState({ isShareModalOpen: true });
|
||||||
|
}
|
||||||
detachedPreviewBtnHandler() {
|
detachedPreviewBtnHandler() {
|
||||||
trackEvent('ui', 'detachPreviewBtnClick');
|
trackEvent('ui', 'detachPreviewBtnClick');
|
||||||
|
|
||||||
@ -1641,10 +1650,11 @@ export default class App extends Component {
|
|||||||
profileBtnHandler={this.profileBtnClickHandler.bind(this)}
|
profileBtnHandler={this.profileBtnClickHandler.bind(this)}
|
||||||
addLibraryBtnHandler={this.openAddLibrary.bind(this)}
|
addLibraryBtnHandler={this.openAddLibrary.bind(this)}
|
||||||
assetsBtnHandler={this.assetsBtnClickHandler.bind(this)}
|
assetsBtnHandler={this.assetsBtnClickHandler.bind(this)}
|
||||||
|
shareBtnHandler={this.shareBtnClickHandler.bind(this)}
|
||||||
runBtnClickHandler={this.runBtnClickHandler.bind(this)}
|
runBtnClickHandler={this.runBtnClickHandler.bind(this)}
|
||||||
isFetchingItems={this.state.isFetchingItems}
|
isFetchingItems={this.state.isFetchingItems}
|
||||||
isSaving={this.state.isSaving}
|
isSaving={this.state.isSaving}
|
||||||
title={this.state.currentItem.title}
|
currentItem={this.state.currentItem}
|
||||||
titleInputBlurHandler={this.titleInputBlurHandler.bind(this)}
|
titleInputBlurHandler={this.titleInputBlurHandler.bind(this)}
|
||||||
user={this.state.user}
|
user={this.state.user}
|
||||||
isAutoPreviewOn={this.state.prefs.autoPreview}
|
isAutoPreviewOn={this.state.prefs.autoPreview}
|
||||||
@ -1791,6 +1801,22 @@ export default class App extends Component {
|
|||||||
logoutBtnHandler={this.logout.bind(this)}
|
logoutBtnHandler={this.logout.bind(this)}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
show={this.state.isShareModalOpen}
|
||||||
|
closeHandler={() => this.setState({ isShareModalOpen: false })}
|
||||||
|
>
|
||||||
|
<Share
|
||||||
|
user={this.state.user}
|
||||||
|
item={this.state.currentItem}
|
||||||
|
onVisibilityChange={visibility => {
|
||||||
|
const item = {
|
||||||
|
...this.state.currentItem,
|
||||||
|
isPublic: visibility
|
||||||
|
};
|
||||||
|
this.setState({ currentItem: item });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
<HelpModal
|
<HelpModal
|
||||||
show={this.state.isHelpModalOpen}
|
show={this.state.isHelpModalOpen}
|
||||||
closeHandler={() => this.setState({ isHelpModalOpen: false })}
|
closeHandler={() => this.setState({ isHelpModalOpen: false })}
|
||||||
|
13
src/db.js
13
src/db.js
@ -167,6 +167,18 @@ import { log } from './utils';
|
|||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getPublicItemCount(userId) {
|
||||||
|
const remoteDb = await getDb();
|
||||||
|
return remoteDb
|
||||||
|
.collection('items')
|
||||||
|
.where('createdBy', '==', userId)
|
||||||
|
.where('isPublic', '==', true)
|
||||||
|
.get()
|
||||||
|
.then(snapShot => {
|
||||||
|
return snapShot.size;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
window.db = {
|
window.db = {
|
||||||
getDb,
|
getDb,
|
||||||
getUser,
|
getUser,
|
||||||
@ -174,6 +186,7 @@ import { log } from './utils';
|
|||||||
setUserLastSeenVersion,
|
setUserLastSeenVersion,
|
||||||
getSettings,
|
getSettings,
|
||||||
fetchItem,
|
fetchItem,
|
||||||
|
getPublicItemCount,
|
||||||
local: dbLocalAlias,
|
local: dbLocalAlias,
|
||||||
sync: dbSyncAlias
|
sync: dbSyncAlias
|
||||||
};
|
};
|
||||||
|
@ -2133,6 +2133,7 @@ while the theme CSS file is loading */
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pro-badge {
|
.pro-badge {
|
||||||
|
display: inline-block;
|
||||||
padding: 0.1rem 0.3rem;
|
padding: 0.1rem 0.3rem;
|
||||||
background-color: #fff91f;
|
background-color: #fff91f;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
Reference in New Issue
Block a user