-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Url share #147
Url share #147
Changes from 35 commits
9f00715
6660793
f51c2ff
4c27595
03553bf
cc6d9fc
d08d81c
0e7f709
9dc0063
326b8b7
c8d8200
2ffe770
703d669
06dc08d
81eb7bb
c93dfaf
e9d9ec7
2872621
49593c3
14824d0
f00cc87
b9df6f0
c71387a
0affc09
3267552
ad2ab27
ddaeaf3
194fa50
3f52ff5
0ce1ed2
cb37b93
ec92fd8
a25b047
4dad523
a915f09
651e3dc
d658df5
10d1229
56d65be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
REACT_APP_API_URL=http://localhost:3001 | ||
REACT_APP_PB_APP_URL=http://localhost:3000 | ||
REACT_APP_VERSION=$npm_package_version | ||
REACT_APP_GOOGLE_ANALYTICS_KEY=G-xxxxxx #Not necessary, can be omitted for development |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { CreatorActionButton } from "../CreatorActionButton"; | ||
import DownloadIcon from '@mui/icons-material/Download'; | ||
import { useContext, useState } from "react"; | ||
import { Dialog, DialogContent, DialogTitle, InputAdornment, Stack, TextField } from "@mui/material"; | ||
import { CreatorContext } from "../../CreatorContext"; | ||
import { ShareButtons, CopyToClipboardButton } from "./ShareModalButtons"; | ||
import { useTranslation } from "react-i18next"; | ||
|
||
export const ShareButton = () => { | ||
|
||
const [dialogOpen, setDialogOpen] = useState<boolean>(false) | ||
|
||
return <> | ||
<ShareDialog open={dialogOpen} setDialogOpen={setDialogOpen} /> | ||
<CreatorActionButton onClick={() => { setDialogOpen(true) }} startIcon={<DownloadIcon />} nametag='share' isshortversion={true} /> | ||
</> | ||
|
||
} | ||
|
||
const ShareDialog = ({ open, setDialogOpen }: { open: boolean, setDialogOpen: (open: boolean) => void }) => { | ||
|
||
const { t } = useTranslation('creator'); | ||
|
||
return <> | ||
<Dialog open={open} onClose={() => { setDialogOpen(false) }}> | ||
<DialogTitle>{t('editor.buttons.share')}</DialogTitle> | ||
<DialogContent > | ||
<ShareModal /> | ||
</DialogContent> | ||
</Dialog > | ||
</> | ||
} | ||
|
||
export const ShareModal = () => { | ||
const { sharedId } = useContext(CreatorContext) | ||
|
||
const sharedLink = process.env.REACT_APP_PB_APP_URL + `/#/desafio/guardado/${sharedId}` | ||
|
||
return <Stack> | ||
{sharedId ? | ||
<Stack direction='row'> | ||
<TextField | ||
sx={{ width: '100%', margin: 1}} | ||
defaultValue={sharedLink} | ||
InputProps={{ | ||
readOnly: true, | ||
endAdornment: ( | ||
<InputAdornment position="end"> | ||
<CopyToClipboardButton textToCopy={sharedLink} /> | ||
</InputAdornment> | ||
) | ||
}} | ||
/> | ||
</Stack> | ||
: <></> | ||
} | ||
<ShareButtons /> | ||
</Stack> | ||
} | ||
|
||
|
||
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Estos componentes quedaron re prolijos, gente, felicitaciones ❤️ . Estoy contento con cómo quedó. Hice un comment abajo sobre un posible refactor y pequeño cambio de lógica. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import ShareIcon from '@mui/icons-material/Share'; | ||
import SaveIcon from '@mui/icons-material/Save'; | ||
import ContentCopyIcon from '@mui/icons-material/ContentCopy'; | ||
import { ReactNode, useContext, useState } from "react" | ||
import { IconButtonTooltip } from "../../SceneEdition/IconButtonTooltip" | ||
import { Snackbar, Stack, Tooltip } from "@mui/material" | ||
import { CreatorContext } from '../../CreatorContext'; | ||
import { LocalStorage } from '../../../../../localStorage'; | ||
import { PilasBloquesApi } from '../../../../../pbApi'; | ||
import { CreatorActionButton } from '../CreatorActionButton'; | ||
import { DialogSnackbar } from '../../../../dialogSnackbar/DialogSnackbar'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { SerializedChallenge } from '../../../../serializedChallenge'; | ||
import { DownloadButton } from '../DownloadButton'; | ||
|
||
export const CopyToClipboardButton = ({ textToCopy }: { textToCopy: string }) => { | ||
|
||
const [openSnackbar, setOpenSnackbar] = useState(false) | ||
|
||
const { t } = useTranslation('creator'); | ||
|
||
const handleClick = () => { | ||
setOpenSnackbar(true) | ||
navigator.clipboard.writeText(textToCopy) | ||
} | ||
|
||
return <> | ||
<IconButtonTooltip icon={<ContentCopyIcon />} onClick={handleClick} tooltip={t('editor.buttons.copyToClipboard')} /> | ||
<Snackbar | ||
open={openSnackbar} | ||
onClose={() => setOpenSnackbar(false)} | ||
autoHideDuration={2000} | ||
message={t('editor.buttons.copiedToClipboard')} | ||
/> | ||
</> | ||
} | ||
|
||
export const ShareButtons = () => { | ||
const { sharedId } = useContext(CreatorContext) | ||
|
||
return <> | ||
<Stack direction="row" justifyContent="space-between" alignItems='center'> | ||
{sharedId ? <SaveButton /> : <ShareUrlButton />} | ||
tfloxolodeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<DownloadButton /> | ||
</Stack> | ||
</> | ||
} | ||
|
||
const ShareUrlButton = () => { | ||
|
||
const shareChallenge = async (): Promise<string> => { | ||
const challenge: SerializedChallenge = LocalStorage.getCreatorChallenge()! | ||
const sharedChallenge = await PilasBloquesApi.shareChallenge(challenge) | ||
return sharedChallenge.sharedId | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Esta lógica está repetida en ambos ShareUrlButton y SaveButton. Debería estar abajo en ChallengeUpsertButton. el parámetro challengeUpsert no debería ser necesario. |
||
} | ||
|
||
return <ChallengeUpsertButton Icon={<ShareIcon />} nametag="shareUrl" challengeUpsert={shareChallenge} /> | ||
} | ||
const SaveButton = () => { | ||
const [openSnackbar, setOpenSnackbar] = useState(false) | ||
|
||
const { t } = useTranslation('creator'); | ||
|
||
const saveChallenge = async (): Promise<string> => { | ||
const savedChallenge = await PilasBloquesApi.saveChallenge(LocalStorage.getCreatorChallenge()!) | ||
setOpenSnackbar(true) | ||
return savedChallenge.sharedId | ||
} | ||
|
||
return <> | ||
<ChallengeUpsertButton Icon={<SaveIcon />} nametag="save" challengeUpsert={saveChallenge} /> | ||
<Snackbar | ||
open={openSnackbar} | ||
onClose={() => setOpenSnackbar(false)} | ||
autoHideDuration={2000} | ||
message={t('editor.buttons.savedCorrectly')} | ||
/> | ||
</> | ||
} | ||
|
||
export const ChallengeUpsertButton = ({ Icon, challengeUpsert, nametag }: { Icon: ReactNode, nametag: string, challengeUpsert: () => Promise<string> }) => { | ||
|
||
const { setSharedId } = useContext(CreatorContext) | ||
const userLoggedIn = !!LocalStorage.getUser() | ||
const [serverError, setServerError] = useState<boolean>(false) | ||
const { t } = useTranslation('creator'); | ||
|
||
const handleClick = async () => { | ||
try { | ||
setSharedId(await challengeUpsert()) | ||
} | ||
catch (error) { | ||
setServerError(true) | ||
} | ||
} | ||
|
||
return <> | ||
<Tooltip title={!userLoggedIn ? t('editor.loginWarning') : ''} followCursor> | ||
<div> | ||
<CreatorActionButton data-testid="upsertButton" onClick={handleClick} disabled={!userLoggedIn} startIcon={Icon} variant='contained' nametag={nametag} /> | ||
</div> | ||
</Tooltip> | ||
<DialogSnackbar open={serverError} onClose={() => setServerError(false)} message={t('editor.serverError')} /> | ||
</> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,20 +30,20 @@ export const CreatorViewMode = () => { | |
return (<> | ||
{challengeExists ? ( | ||
<> | ||
<Header CenterComponent={<CreatorViewHeader challenge={challengeBeingEdited} />} SubHeader={<EditorSubHeader viewButton={<ReturnToEditionButton />} />} /> | ||
<Header CenterComponent={<CreatorViewHeader title={challengeBeingEdited.title} />} SubHeader={<EditorSubHeader viewButton={<ReturnToEditionButton />} />} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No entendí por qué pasa esto ahora... |
||
<EmberView height='calc(100% - var(--creator-subheader-height))' path={EMBER_IMPORTED_CHALLENGE_PATH} /> | ||
</> | ||
) : <></>} | ||
</>) | ||
} | ||
|
||
const CreatorViewHeader = ({ challenge }: { challenge: SerializedChallenge }) => { | ||
export const CreatorViewHeader = ({ title }: { title: string }) => { | ||
const { t } = useTranslation('creator') | ||
|
||
return <BetaBadge smaller={true}> | ||
<PBreadcrumbs> | ||
<HeaderText text={t("editor.previewModeHeader")} /> | ||
<Typography>{challenge.title}</Typography> | ||
<Typography>{title}</Typography> | ||
</PBreadcrumbs> | ||
</BetaBadge> | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
La de arriba y esta pueden ser directamente
(no sé bien cómo deben ser los caracteres finales, pero puede ser así, no son secretas esas url)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Idem en los otros jobs)