Skip to content
Snippets Groups Projects
Commit fa8c25cd authored by Albin Henriksson's avatar Albin Henriksson
Browse files

Resolve "Implement background image"

parent ef67d2ab
No related branches found
No related tags found
1 merge request!109Resolve "Implement background image"
Pipeline #42874 passed with warnings
import { ListItem, ListItemText, Typography } from '@material-ui/core'
import React, { useState } from 'react'
import { useAppDispatch, useAppSelector } from '../../../hooks'
import {
AddButton,
AddBackgroundButton,
Center,
HiddenInput,
ImportedImage,
SettingsList,
ImageNameText,
ImageTextContainer,
} from './styled'
import CloseIcon from '@material-ui/icons/Close'
import axios from 'axios'
import { Media } from '../../../interfaces/ApiModels'
import { getEditorCompetition } from '../../../actions/editor'
import { uploadFile } from '../../../utils/uploadImage'
type BackgroundImageSelectProps = {
variant: 'competition' | 'slide'
}
const BackgroundImageSelect = ({ variant }: BackgroundImageSelectProps) => {
const activeSlideId = useAppSelector((state) => state.editor.activeSlideId)
const backgroundImage = useAppSelector((state) => {
if (variant === 'competition') return state.editor.competition.background_image
else return state.editor.competition.slides.find((slide) => slide.id === activeSlideId)?.background_image
})
const competitionId = useAppSelector((state) => state.editor.competition.id)
const dispatch = useAppDispatch()
const updateBackgroundImage = async (mediaId: number) => {
// Creates a new image component on the database using API call.
if (variant === 'competition') {
await axios
.put(`/api/competitions/${competitionId}`, { background_image_id: mediaId })
.then(() => {
dispatch(getEditorCompetition(competitionId.toString()))
})
.catch(console.log)
} else {
await axios
.put(`/api/competitions/${competitionId}/slides/${activeSlideId}`, { background_image_id: mediaId })
.then(() => {
dispatch(getEditorCompetition(competitionId.toString()))
})
.catch(console.log)
}
}
const removeBackgroundImage = async () => {
// Removes background image media and from competition using API calls.
await axios.delete(`/api/media/images/${backgroundImage?.id}`).catch(console.log)
if (variant === 'competition') {
await axios
.put(`/api/competitions/${competitionId}`, { background_image_id: null })
.then(() => {
dispatch(getEditorCompetition(competitionId.toString()))
})
.catch(console.log)
} else {
await axios
.put(`/api/competitions/${competitionId}/slides/${activeSlideId}`, { background_image_id: null })
.then(() => {
dispatch(getEditorCompetition(competitionId.toString()))
})
.catch(console.log)
}
}
const handleFileSelected = async (e: React.ChangeEvent<HTMLInputElement>) => {
// Reads the selected image file and uploads it to the server.
// Creates a new image component containing the file.
if (e.target.files !== null && e.target.files[0]) {
const files = Array.from(e.target.files)
const file = files[0]
const formData = new FormData()
formData.append('image', file)
const media = await uploadFile(formData, competitionId.toString())
if (media) {
updateBackgroundImage(media.id)
}
}
}
return (
<SettingsList>
{!backgroundImage && (
<ListItem button style={{ padding: 0 }}>
<HiddenInput
accept="image/*"
id="background-button-file"
multiple
type="file"
onChange={handleFileSelected}
/>
<AddBackgroundButton htmlFor="background-button-file">
<Center>
<AddButton variant="button">Välj bakgrundsbild...</AddButton>
</Center>
</AddBackgroundButton>
</ListItem>
)}
{backgroundImage && (
<>
<ListItem divider>
<ImageTextContainer>
<ListItemText>Bakgrundsbild</ListItemText>
<Typography variant="body2">(Bilden bör ha sidförhållande 16:9)</Typography>
</ImageTextContainer>
</ListItem>
<ListItem divider button>
<ImportedImage src={`/static/images/thumbnail_${backgroundImage.filename}`} />
<Center>
<ImageNameText primary={backgroundImage.filename} />
</Center>
<CloseIcon onClick={removeBackgroundImage} />
</ListItem>
</>
)}
</SettingsList>
)
}
export default BackgroundImageSelect
......@@ -17,6 +17,7 @@ import { getEditorCompetition } from '../../../actions/editor'
import { useAppDispatch, useAppSelector } from '../../../hooks'
import { City } from '../../../interfaces/ApiModels'
import Teams from './Teams'
import BackgroundImageSelect from './BackgroundImageSelect'
interface CompetitionParams {
competitionId: string
......@@ -92,17 +93,7 @@ const CompetitionSettings: React.FC = () => {
<Teams competitionId={competitionId} />
<SettingsList>
<ListItem button>
<ImportedImage
id="temp source, todo: add image source to elements of pictureList"
src="https://i1.wp.com/stickoutmedia.se/wp-content/uploads/2021/01/placeholder-3.png?ssl=1"
/>
<Center>
<ListItemText>Välj bakgrundsbild ...</ListItemText>
</Center>
</ListItem>
</SettingsList>
<BackgroundImageSelect variant="competition" />
</PanelContainer>
)
}
......
......@@ -26,6 +26,9 @@ const RndComponent = ({ component, width, height, scale }: RndComponentProps) =>
const competitionId = useAppSelector((state) => state.editor.competition.id)
const slideId = useAppSelector((state) => state.editor.activeSlideId)
const [shiftPressed, setShiftPressed] = useState(false)
const typeName = useAppSelector(
(state) => state.types.componentTypes.find((componentType) => componentType.id === component.type_id)?.name
)
const handleUpdatePos = (pos: Position) => {
axios.put(`/api/competitions/${competitionId}/slides/${slideId}/components/${component.id}`, {
x: pos.x,
......@@ -98,6 +101,8 @@ const RndComponent = ({ component, width, height, scale }: RndComponentProps) =>
setCurrentPos({ x: d.x / scale, y: d.y / scale })
handleUpdatePos({ x: d.x / scale, y: d.y / scale })
}}
//Makes text appear on images
style={{ zIndex: typeName === 'Text' ? 2 : 1 }}
lockAspectRatio={shiftPressed}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
......@@ -114,6 +119,7 @@ const RndComponent = ({ component, width, height, scale }: RndComponentProps) =>
w: ref.offsetWidth / scale,
h: ref.offsetHeight / scale,
})
setCurrentPos({ x: position.x / scale, y: position.y / scale })
}}
>
{hover && (
......
......@@ -17,6 +17,17 @@ const SlideDisplay = ({ variant, activeViewTypeId }: SlideDisplayProps) => {
return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.components
return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.slide?.id)?.components
})
const competitionBackgroundImage = useAppSelector((state) => {
if (variant === 'editor') return state.editor.competition.background_image
return state.presentation.competition.background_image
})
const slideBackgroundImage = useAppSelector((state) => {
if (variant === 'editor')
return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.background_image
return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.slide.id)
?.background_image
})
const dispatch = useAppDispatch()
const editorPaperRef = useRef<HTMLDivElement>(null)
const [width, setWidth] = useState(0)
......@@ -42,6 +53,16 @@ const SlideDisplay = ({ variant, activeViewTypeId }: SlideDisplayProps) => {
<SlideEditorContainer>
<SlideEditorContainerRatio>
<SlideEditorPaper ref={editorPaperRef}>
{(competitionBackgroundImage || slideBackgroundImage) && (
<img
src={`/static/images/${
slideBackgroundImage ? slideBackgroundImage.filename : competitionBackgroundImage?.filename
}`}
height={height}
width={width}
draggable={false}
/>
)}
{components &&
components
.filter((component) => component.view_type_id === activeViewTypeId)
......
......@@ -12,6 +12,7 @@ import Timer from './slideSettingsComponents/Timer'
import Images from './slideSettingsComponents/Images'
import Texts from './slideSettingsComponents/Texts'
import QuestionSettings from './slideSettingsComponents/QuestionSettings'
import BackgroundImageSelect from './BackgroundImageSelect'
interface CompetitionParams {
competitionId: string
......@@ -56,17 +57,7 @@ const SlideSettings: React.FC = () => {
<Images activeViewTypeId={activeViewTypeId} activeSlide={activeSlide} competitionId={competitionId} />
)}
<SettingsList>
<ListItem button>
<ImportedImage
id="temp source, todo: add image source to elements of pictureList"
src="https://i1.wp.com/stickoutmedia.se/wp-content/uploads/2021/01/placeholder-3.png?ssl=1"
/>
<Center>
<ListItemText>Välj bakgrundsbild ...</ListItemText>
</Center>
</ListItem>
</SettingsList>
<BackgroundImageSelect variant="slide" />
</PanelContainer>
)
}
......
......@@ -58,7 +58,7 @@ const Images = ({ activeViewTypeId, activeSlide, competitionId }: ImagesProps) =
formData.append('image', file)
const response = await uploadFile(formData)
if (response) {
const newComponent = createImageComponent(response)
createImageComponent(response)
}
}
}
......
......@@ -9,6 +9,7 @@ import {
ListItem,
Select,
InputLabel,
ListItemText,
} from '@material-ui/core'
import styled from 'styled-components'
......@@ -71,6 +72,14 @@ export const Center = styled.div`
width: 100%;
`
export const ImageTextContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
`
export const PanelContainer = styled.div`
padding: 10px;
width: 100%;
......@@ -91,7 +100,16 @@ export const Clickable = styled.div`
export const AddImageButton = styled.label`
padding: 8px 13px 8px 13px;
cursor: 'pointer';
display: flex;
justify-content: center;
text-align: center;
height: 100%;
width: 100%;
cursor: pointer;
`
export const AddBackgroundButton = styled.label`
padding: 16px 29px 16px 29px;
display: flex;
justify-content: center;
text-align: center;
......@@ -126,3 +144,7 @@ export const HoverContainer = styled.div<HoverContainerProps>`
padding: ${(props) => (props.hover ? 0 : 1)}px;
border: solid ${(props) => (props.hover ? 1 : 0)}px;
`
export const ImageNameText = styled(ListItemText)`
word-break: break-all;
`
import axios from 'axios'
import { getEditorCompetition } from '../actions/editor'
import { Media } from '../interfaces/ApiModels'
import store from '../store'
export const uploadFile = async (formData: FormData, competitionId: string) => {
// Uploads the file to the server and creates a Media object in database.
// Returns media object data.
return await axios
.post(`/api/media/images`, formData)
.then((response) => {
getEditorCompetition(competitionId)(store.dispatch, store.getState)
return response.data as Media
})
.catch(console.log)
}
......@@ -87,6 +87,12 @@ def _add_items():
w = random.randrange(150, 400)
h = random.randrange(150, 400)
dbc.add.component(1, item_slide.id, 1, x, y, w, h, text=f"hej{k}")
for k in range(3):
x = random.randrange(1, 500)
y = random.randrange(1, 500)
w = random.randrange(150, 400)
h = random.randrange(150, 400)
dbc.add.component(1, item_slide.id, 3, x, y, w, h, text=f"hej{k}")
# item_slide = dbc.add.slide(item_comp)
# item_slide.title = f"Slide {len(item_comp.slides)}"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment