Merge branch 'master' into geographic-map-page
This commit is contained in:
commit
db64d3eb1b
|
@ -54,7 +54,7 @@ type ComplexityRoot struct {
|
|||
Album struct {
|
||||
FilePath func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Media func(childComplexity int, filter *models.Filter) int
|
||||
Media func(childComplexity int, filter *models.Filter, onlyFavorites *bool) int
|
||||
Owner func(childComplexity int) int
|
||||
ParentAlbum func(childComplexity int) int
|
||||
Path func(childComplexity int) int
|
||||
|
@ -146,7 +146,7 @@ type ComplexityRoot struct {
|
|||
Album func(childComplexity int, id int) int
|
||||
MapboxToken func(childComplexity int) int
|
||||
Media func(childComplexity int, id int) int
|
||||
MyAlbums func(childComplexity int, filter *models.Filter, onlyRoot *bool, showEmpty *bool) int
|
||||
MyAlbums func(childComplexity int, filter *models.Filter, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) int
|
||||
MyMedia func(childComplexity int, filter *models.Filter) int
|
||||
MyMediaGeoJSON func(childComplexity int) int
|
||||
MyUser func(childComplexity int) int
|
||||
|
@ -212,7 +212,7 @@ type ComplexityRoot struct {
|
|||
}
|
||||
|
||||
type AlbumResolver interface {
|
||||
Media(ctx context.Context, obj *models.Album, filter *models.Filter) ([]*models.Media, error)
|
||||
Media(ctx context.Context, obj *models.Album, filter *models.Filter, onlyFavorites *bool) ([]*models.Media, error)
|
||||
SubAlbums(ctx context.Context, obj *models.Album, filter *models.Filter) ([]*models.Album, error)
|
||||
ParentAlbum(ctx context.Context, obj *models.Album) (*models.Album, error)
|
||||
Owner(ctx context.Context, obj *models.Album) (*models.User, error)
|
||||
|
@ -253,7 +253,7 @@ type QueryResolver interface {
|
|||
SiteInfo(ctx context.Context) (*models.SiteInfo, error)
|
||||
User(ctx context.Context, filter *models.Filter) ([]*models.User, error)
|
||||
MyUser(ctx context.Context) (*models.User, error)
|
||||
MyAlbums(ctx context.Context, filter *models.Filter, onlyRoot *bool, showEmpty *bool) ([]*models.Album, error)
|
||||
MyAlbums(ctx context.Context, filter *models.Filter, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error)
|
||||
Album(ctx context.Context, id int) (*models.Album, error)
|
||||
MyMedia(ctx context.Context, filter *models.Filter) ([]*models.Media, error)
|
||||
Media(ctx context.Context, id int) (*models.Media, error)
|
||||
|
@ -313,7 +313,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Album.Media(childComplexity, args["filter"].(*models.Filter)), true
|
||||
return e.complexity.Album.Media(childComplexity, args["filter"].(*models.Filter), args["onlyFavorites"].(*bool)), true
|
||||
|
||||
case "Album.owner":
|
||||
if e.complexity.Album.Owner == nil {
|
||||
|
@ -879,7 +879,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.MyAlbums(childComplexity, args["filter"].(*models.Filter), args["onlyRoot"].(*bool), args["showEmpty"].(*bool)), true
|
||||
return e.complexity.Query.MyAlbums(childComplexity, args["filter"].(*models.Filter), args["onlyRoot"].(*bool), args["showEmpty"].(*bool), args["onlyWithFavorites"].(*bool)), true
|
||||
|
||||
case "Query.myMedia":
|
||||
if e.complexity.Query.MyMedia == nil {
|
||||
|
@ -1299,6 +1299,8 @@ type Query {
|
|||
onlyRoot: Boolean
|
||||
"Return also albums with no media directly in them"
|
||||
showEmpty: Boolean
|
||||
"Show only albums having favorites"
|
||||
onlyWithFavorites: Boolean
|
||||
): [Album!]!
|
||||
"Get album by id, user must own the album or be admin"
|
||||
album(id: Int!): Album!
|
||||
|
@ -1454,7 +1456,11 @@ type Album {
|
|||
id: Int!
|
||||
title: String!
|
||||
"The media inside this album"
|
||||
media(filter: Filter): [Media!]!
|
||||
media(
|
||||
filter: Filter,
|
||||
"Return only the favorited media"
|
||||
onlyFavorites: Boolean
|
||||
): [Media!]!
|
||||
"The albums contained in this album"
|
||||
subAlbums(filter: Filter): [Album!]!
|
||||
"The album witch contains this album"
|
||||
|
@ -1576,6 +1582,14 @@ func (ec *executionContext) field_Album_media_args(ctx context.Context, rawArgs
|
|||
}
|
||||
}
|
||||
args["filter"] = arg0
|
||||
var arg1 *bool
|
||||
if tmp, ok := rawArgs["onlyFavorites"]; ok {
|
||||
arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["onlyFavorites"] = arg1
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
@ -2041,6 +2055,14 @@ func (ec *executionContext) field_Query_myAlbums_args(ctx context.Context, rawAr
|
|||
}
|
||||
}
|
||||
args["showEmpty"] = arg2
|
||||
var arg3 *bool
|
||||
if tmp, ok := rawArgs["onlyWithFavorites"]; ok {
|
||||
arg3, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["onlyWithFavorites"] = arg3
|
||||
return args, nil
|
||||
}
|
||||
|
||||
|
@ -2288,7 +2310,7 @@ func (ec *executionContext) _Album_media(ctx context.Context, field graphql.Coll
|
|||
fc.Args = args
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Album().Media(rctx, obj, args["filter"].(*models.Filter))
|
||||
return ec.resolvers.Album().Media(rctx, obj, args["filter"].(*models.Filter), args["onlyFavorites"].(*bool))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
|
@ -4800,7 +4822,7 @@ func (ec *executionContext) _Query_myAlbums(ctx context.Context, field graphql.C
|
|||
fc.Args = args
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Query().MyAlbums(rctx, args["filter"].(*models.Filter), args["onlyRoot"].(*bool), args["showEmpty"].(*bool))
|
||||
return ec.resolvers.Query().MyAlbums(rctx, args["filter"].(*models.Filter), args["onlyRoot"].(*bool), args["showEmpty"].(*bool), args["onlyWithFavorites"].(*bool))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/viktorstrate/photoview/api/graphql/models"
|
||||
)
|
||||
|
||||
func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter, onlyRoot *bool, showEmpty *bool) ([]*models.Album, error) {
|
||||
func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, auth.ErrUnauthorized
|
||||
|
@ -22,8 +22,13 @@ func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter, onl
|
|||
|
||||
var rows *sql.Rows
|
||||
|
||||
filterEmpty := " AND EXISTS (SELECT * FROM media WHERE album_id = album.album_id) "
|
||||
if showEmpty != nil && *showEmpty == true {
|
||||
filterFavorites := " AND favorite = 1"
|
||||
if onlyWithFavorites == nil || *onlyWithFavorites == false {
|
||||
filterFavorites = ""
|
||||
}
|
||||
|
||||
filterEmpty := " AND EXISTS (SELECT * FROM media WHERE album_id = album.album_id" + filterFavorites + ") "
|
||||
if showEmpty != nil && *showEmpty == true && (onlyWithFavorites == nil || *onlyWithFavorites == false) {
|
||||
filterEmpty = ""
|
||||
}
|
||||
|
||||
|
@ -72,20 +77,25 @@ func (r *Resolver) Album() api.AlbumResolver {
|
|||
|
||||
type albumResolver struct{ *Resolver }
|
||||
|
||||
func (r *albumResolver) Media(ctx context.Context, obj *models.Album, filter *models.Filter) ([]*models.Media, error) {
|
||||
func (r *albumResolver) Media(ctx context.Context, obj *models.Album, filter *models.Filter, onlyFavorites *bool) ([]*models.Media, error) {
|
||||
|
||||
filterSQL, err := filter.FormatSQL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filterFavorites := " AND media.favorite = 1 "
|
||||
if onlyFavorites == nil || *onlyFavorites == false {
|
||||
filterFavorites = ""
|
||||
}
|
||||
|
||||
mediaRows, err := r.Database.Query(`
|
||||
SELECT media.* FROM album, media
|
||||
WHERE album.album_id = ? AND media.album_id = album.album_id
|
||||
AND media.media_id IN (
|
||||
SELECT media_id FROM media_url WHERE media_url.media_id = media.media_id
|
||||
)
|
||||
`+filterSQL, obj.AlbumID)
|
||||
`+filterFavorites+filterSQL, obj.AlbumID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ type Query {
|
|||
onlyRoot: Boolean
|
||||
"Return also albums with no media directly in them"
|
||||
showEmpty: Boolean
|
||||
"Show only albums having favorites"
|
||||
onlyWithFavorites: Boolean
|
||||
): [Album!]!
|
||||
"Get album by id, user must own the album or be admin"
|
||||
album(id: Int!): Album!
|
||||
|
@ -185,7 +187,11 @@ type Album {
|
|||
id: Int!
|
||||
title: String!
|
||||
"The media inside this album"
|
||||
media(filter: Filter): [Media!]!
|
||||
media(
|
||||
filter: Filter,
|
||||
"Return only the favorited media"
|
||||
onlyFavorites: Boolean
|
||||
): [Media!]!
|
||||
"The albums contained in this album"
|
||||
subAlbums(filter: Filter): [Album!]!
|
||||
"The album witch contains this album"
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React, { Component } from 'react'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import ReactRouterPropTypes from 'react-router-prop-types'
|
||||
import gql from 'graphql-tag'
|
||||
import { Query } from 'react-apollo'
|
||||
import AlbumGallery from '../../components/albumGallery/AlbumGallery'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const albumQuery = gql`
|
||||
query albumQuery($id: Int!) {
|
||||
query albumQuery($id: Int!, $onlyFavorites: Boolean) {
|
||||
album(id: $id) {
|
||||
id
|
||||
title
|
||||
|
@ -18,7 +19,10 @@ const albumQuery = gql`
|
|||
}
|
||||
}
|
||||
}
|
||||
media(filter: { order_by: "title", order_direction: DESC }) {
|
||||
media(
|
||||
filter: { order_by: "title", order_direction: DESC }
|
||||
onlyFavorites: $onlyFavorites
|
||||
) {
|
||||
id
|
||||
type
|
||||
thumbnail {
|
||||
|
@ -38,15 +42,60 @@ const albumQuery = gql`
|
|||
}
|
||||
`
|
||||
|
||||
let refetchNeededAll = false
|
||||
let refetchNeededFavorites = false
|
||||
|
||||
function AlbumPage({ match }) {
|
||||
const albumId = match.params.id
|
||||
const [onlyFavorites, setOnlyFavorites] = useState(
|
||||
match.params.subPage === 'favorites'
|
||||
)
|
||||
|
||||
const toggleFavorites = useCallback(
|
||||
refetch => {
|
||||
const newState = !onlyFavorites
|
||||
if (
|
||||
(refetchNeededAll && !newState) ||
|
||||
(refetchNeededFavorites && newState)
|
||||
) {
|
||||
refetch({ id: albumId, onlyFavorites: newState }).then(() => {
|
||||
if (onlyFavorites) {
|
||||
refetchNeededFavorites = false
|
||||
} else {
|
||||
refetchNeededAll = false
|
||||
}
|
||||
setOnlyFavorites(newState)
|
||||
})
|
||||
} else {
|
||||
setOnlyFavorites(newState)
|
||||
}
|
||||
history.replaceState(
|
||||
{},
|
||||
'',
|
||||
'/album/' + albumId + (newState ? '/favorites' : '')
|
||||
)
|
||||
},
|
||||
[onlyFavorites, setOnlyFavorites]
|
||||
)
|
||||
|
||||
return (
|
||||
<Query query={albumQuery} variables={{ id: albumId }}>
|
||||
{({ loading, error, data }) => {
|
||||
<Query query={albumQuery} variables={{ id: albumId, onlyFavorites }}>
|
||||
{({ loading, error, data, refetch }) => {
|
||||
if (error) return <div>Error</div>
|
||||
|
||||
return <AlbumGallery album={data && data.album} loading={loading} />
|
||||
return (
|
||||
<AlbumGallery
|
||||
album={data && data.album}
|
||||
loading={loading}
|
||||
showFavoritesToggle
|
||||
setOnlyFavorites={() => {
|
||||
toggleFavorites(refetch)
|
||||
}}
|
||||
onlyFavorites={onlyFavorites}
|
||||
onFavorite={() =>
|
||||
(refetchNeededAll = refetchNeededFavorites = true)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
|
@ -54,6 +103,12 @@ function AlbumPage({ match }) {
|
|||
|
||||
AlbumPage.propTypes = {
|
||||
...ReactRouterPropTypes,
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
subPage: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
export default AlbumPage
|
||||
|
|
|
@ -4,14 +4,22 @@ import gql from 'graphql-tag'
|
|||
import { Query } from 'react-apollo'
|
||||
import PhotoGallery from '../../components/photoGallery/PhotoGallery'
|
||||
import AlbumTitle from '../../components/AlbumTitle'
|
||||
import { Checkbox } from 'semantic-ui-react'
|
||||
import styled from 'styled-components'
|
||||
import { authToken } from '../../authentication'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const photoQuery = gql`
|
||||
query allPhotosPage {
|
||||
myAlbums(filter: { order_by: "title", order_direction: ASC, limit: 100 }) {
|
||||
query allPhotosPage($onlyWithFavorites: Boolean) {
|
||||
myAlbums(
|
||||
filter: { order_by: "title", order_direction: ASC, limit: 100 }
|
||||
onlyWithFavorites: $onlyWithFavorites
|
||||
) {
|
||||
title
|
||||
id
|
||||
media(
|
||||
filter: { order_by: "media.title", order_direction: DESC, limit: 12 }
|
||||
onlyFavorites: $onlyWithFavorites
|
||||
) {
|
||||
id
|
||||
title
|
||||
|
@ -35,6 +43,10 @@ const photoQuery = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const FavoritesCheckbox = styled(Checkbox)`
|
||||
margin: 0.5rem 0 0 0;
|
||||
`
|
||||
|
||||
class PhotosPage extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -43,6 +55,7 @@ class PhotosPage extends Component {
|
|||
activeAlbumIndex: -1,
|
||||
activePhotoIndex: -1,
|
||||
presenting: false,
|
||||
onlyWithFavorites: this.props.match.params.subPage === 'favorites',
|
||||
}
|
||||
|
||||
this.setPresenting = this.setPresenting.bind(this)
|
||||
|
@ -50,6 +63,37 @@ class PhotosPage extends Component {
|
|||
this.previousImage = this.previousImage.bind(this)
|
||||
|
||||
this.albums = []
|
||||
this.refetchNeededFavorites = false
|
||||
this.refetchNeededAll = false
|
||||
}
|
||||
|
||||
favoritesCheckboxClick(refetch) {
|
||||
const onlyWithFavorites = !this.state.onlyWithFavorites
|
||||
history.replaceState(
|
||||
{},
|
||||
'',
|
||||
'/photos' + (onlyWithFavorites ? '/favorites' : '')
|
||||
)
|
||||
|
||||
if (
|
||||
(this.refetchNeededAll && !onlyWithFavorites) ||
|
||||
(this.refetchNeededFavorites && onlyWithFavorites)
|
||||
) {
|
||||
refetch({ onlyWithFavorites }).then(() => {
|
||||
if (onlyWithFavorites) {
|
||||
this.refetchNeededFavorites = false
|
||||
} else {
|
||||
this.refetchNeededAll = false
|
||||
}
|
||||
this.setState({
|
||||
onlyWithFavorites,
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
onlyWithFavorites,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
setActiveImage(album, photo) {
|
||||
|
@ -91,19 +135,35 @@ class PhotosPage extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const showOnlyWithFavorites = this.state.onlyWithFavorites
|
||||
return (
|
||||
<Layout title="Photos">
|
||||
<Query query={photoQuery}>
|
||||
{({ loading, error, data }) => {
|
||||
<Query
|
||||
query={photoQuery}
|
||||
variables={{ onlyWithFavorites: showOnlyWithFavorites }}
|
||||
>
|
||||
{({ loading, error, data, refetch }) => {
|
||||
if (error) return error
|
||||
|
||||
if (loading) return null
|
||||
|
||||
let galleryGroups = []
|
||||
let favoritesSwitch = ''
|
||||
|
||||
this.albums = data.myAlbums
|
||||
|
||||
if (data.myAlbums) {
|
||||
if (data.myAlbums && authToken()) {
|
||||
favoritesSwitch = (
|
||||
<FavoritesCheckbox
|
||||
toggle
|
||||
label="Show only the favorites"
|
||||
onClick={e => e.stopPropagation()}
|
||||
checked={showOnlyWithFavorites}
|
||||
onChange={() => {
|
||||
this.favoritesCheckboxClick(refetch)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
galleryGroups = data.myAlbums.map((album, index) => (
|
||||
<div key={album.id}>
|
||||
<AlbumTitle album={album} />
|
||||
|
@ -111,6 +171,10 @@ class PhotosPage extends Component {
|
|||
onSelectImage={photoIndex => {
|
||||
this.setActiveImage(index, photoIndex)
|
||||
}}
|
||||
onFavorite={() => {
|
||||
this.refetchNeededAll = true
|
||||
this.refetchNeededFavorites = true
|
||||
}}
|
||||
activeIndex={
|
||||
this.state.activeAlbumIndex == index
|
||||
? this.state.activePhotoIndex
|
||||
|
@ -129,15 +193,12 @@ class PhotosPage extends Component {
|
|||
))
|
||||
}
|
||||
|
||||
let activeImage = null
|
||||
if (this.state.activeAlbumIndex != -1) {
|
||||
activeImage =
|
||||
data.myAlbums[this.state.activeAlbumIndex].media[
|
||||
this.state.activePhotoIndex
|
||||
].id
|
||||
}
|
||||
|
||||
return <div>{galleryGroups}</div>
|
||||
return (
|
||||
<div>
|
||||
{favoritesSwitch}
|
||||
{galleryGroups}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Query>
|
||||
</Layout>
|
||||
|
@ -145,4 +206,12 @@ class PhotosPage extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
PhotosPage.propTypes = {
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
subPage: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
export default PhotosPage
|
||||
|
|
|
@ -42,8 +42,8 @@ class Routes extends React.Component {
|
|||
<Route path="/initialSetup" component={InitialSetupPage} />
|
||||
<Route path="/share" component={SharePage} />
|
||||
<AuthorizedRoute exact path="/albums" component={AlbumsPage} />
|
||||
<AuthorizedRoute path="/album/:id" component={AlbumPage} />
|
||||
<AuthorizedRoute path="/photos" component={PhotosPage} />
|
||||
<AuthorizedRoute path="/album/:id/:subPage?" component={AlbumPage} />
|
||||
<AuthorizedRoute path="/photos/:subPage?" component={PhotosPage} />
|
||||
<AuthorizedRoute path="/places" component={PlacesPage} />
|
||||
<AuthorizedRoute admin path="/settings" component={SettingsPage} />
|
||||
<Route path="/" exact render={() => <Redirect to="/photos" />} />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useContext } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Breadcrumb } from 'semantic-ui-react'
|
||||
import { Breadcrumb, Checkbox } from 'semantic-ui-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import styled from 'styled-components'
|
||||
import { Icon } from 'semantic-ui-react'
|
||||
|
@ -33,6 +33,10 @@ const StyledIcon = styled(Icon)`
|
|||
}
|
||||
`
|
||||
|
||||
const FavoritesCheckbox = styled(Checkbox)`
|
||||
margin-bottom: 16px;
|
||||
`
|
||||
|
||||
const SettingsIcon = props => {
|
||||
return <StyledIcon name="settings" size="small" {...props} />
|
||||
}
|
||||
|
@ -49,7 +53,13 @@ const ALBUM_PATH_QUERY = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const AlbumTitle = ({ album, disableLink = false }) => {
|
||||
const AlbumTitle = ({
|
||||
album,
|
||||
disableLink = false,
|
||||
showFavoritesToggle,
|
||||
setOnlyFavorites,
|
||||
onlyFavorites = false,
|
||||
}) => {
|
||||
const [fetchPath, { data: pathData }] = useLazyQuery(ALBUM_PATH_QUERY)
|
||||
const { updateSidebar } = useContext(SidebarContext)
|
||||
|
||||
|
@ -91,23 +101,37 @@ const AlbumTitle = ({ album, disableLink = false }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Header>
|
||||
<Breadcrumb>{breadcrumbSections}</Breadcrumb>
|
||||
{title}
|
||||
{authToken() && (
|
||||
<SettingsIcon
|
||||
onClick={() => {
|
||||
updateSidebar(<AlbumSidebar albumId={album.id} />)
|
||||
}}
|
||||
<>
|
||||
<Header>
|
||||
<Breadcrumb>{breadcrumbSections}</Breadcrumb>
|
||||
{title}
|
||||
{authToken() && (
|
||||
<SettingsIcon
|
||||
onClick={() => {
|
||||
updateSidebar(<AlbumSidebar albumId={album.id} />)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Header>
|
||||
{authToken() && showFavoritesToggle && (
|
||||
<FavoritesCheckbox
|
||||
toggle
|
||||
label="Show only the favorites"
|
||||
checked={onlyFavorites}
|
||||
onClick={e => e.stopPropagation()}
|
||||
onChange={setOnlyFavorites}
|
||||
/>
|
||||
)}
|
||||
</Header>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
AlbumTitle.propTypes = {
|
||||
album: PropTypes.object,
|
||||
disableLink: PropTypes.bool,
|
||||
showFavoritesToggle: PropTypes.bool,
|
||||
setOnlyFavorites: PropTypes.func,
|
||||
onlyFavorites: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default AlbumTitle
|
||||
|
|
|
@ -5,7 +5,15 @@ import AlbumTitle from '../AlbumTitle'
|
|||
import PhotoGallery from '../photoGallery/PhotoGallery'
|
||||
import AlbumBoxes from './AlbumBoxes'
|
||||
|
||||
const AlbumGallery = ({ album, loading = false, customAlbumLink }) => {
|
||||
const AlbumGallery = ({
|
||||
album,
|
||||
loading = false,
|
||||
customAlbumLink,
|
||||
showFavoritesToggle = false,
|
||||
setOnlyFavorites,
|
||||
onlyFavorites = false,
|
||||
onFavorite,
|
||||
}) => {
|
||||
const [imageState, setImageState] = useState({
|
||||
activeImage: -1,
|
||||
presenting: false,
|
||||
|
@ -78,7 +86,13 @@ const AlbumGallery = ({ album, loading = false, customAlbumLink }) => {
|
|||
|
||||
return (
|
||||
<Layout title={album ? album.title : 'Loading album'}>
|
||||
<AlbumTitle album={album} disableLink />
|
||||
<AlbumTitle
|
||||
album={album}
|
||||
disableLink
|
||||
showFavoritesToggle={showFavoritesToggle}
|
||||
onlyFavorites={onlyFavorites}
|
||||
setOnlyFavorites={setOnlyFavorites}
|
||||
/>
|
||||
{subAlbumElement}
|
||||
{
|
||||
<h2
|
||||
|
@ -98,6 +112,7 @@ const AlbumGallery = ({ album, loading = false, customAlbumLink }) => {
|
|||
onSelectImage={index => {
|
||||
setActiveImage(index)
|
||||
}}
|
||||
onFavorite={onFavorite}
|
||||
setPresenting={setPresentingWithHistory}
|
||||
nextImage={nextImage}
|
||||
previousImage={previousImage}
|
||||
|
@ -110,6 +125,10 @@ AlbumGallery.propTypes = {
|
|||
album: PropTypes.object,
|
||||
loading: PropTypes.bool,
|
||||
customAlbumLink: PropTypes.func,
|
||||
showFavoritesToggle: PropTypes.bool,
|
||||
setOnlyFavorites: PropTypes.func,
|
||||
onlyFavorites: PropTypes.bool,
|
||||
onFavorite: PropTypes.func,
|
||||
}
|
||||
|
||||
export default AlbumGallery
|
||||
|
|
|
@ -130,6 +130,7 @@ export const MediaThumbnail = ({
|
|||
index,
|
||||
active,
|
||||
setPresenting,
|
||||
onFavorite,
|
||||
}) => {
|
||||
const [markFavorite] = useMutation(markFavoriteMutation)
|
||||
|
||||
|
@ -141,19 +142,21 @@ export const MediaThumbnail = ({
|
|||
name={media.favorite ? 'heart' : 'heart outline'}
|
||||
onClick={event => {
|
||||
event.stopPropagation()
|
||||
const favorite = !media.favorite
|
||||
markFavorite({
|
||||
variables: {
|
||||
mediaId: media.id,
|
||||
favorite: !media.favorite,
|
||||
favorite: favorite,
|
||||
},
|
||||
optimisticResponse: {
|
||||
favoritePhoto: {
|
||||
favoriteMedia: {
|
||||
id: media.id,
|
||||
favorite: !media.favorite,
|
||||
__typename: 'Photo',
|
||||
favorite: favorite,
|
||||
__typename: 'Media',
|
||||
},
|
||||
},
|
||||
})
|
||||
onFavorite()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -6,6 +6,7 @@ import PresentView from './presentView/PresentView'
|
|||
import PropTypes from 'prop-types'
|
||||
import { SidebarContext } from '../sidebar/Sidebar'
|
||||
import MediaSidebar from '../sidebar/MediaSidebar'
|
||||
import { forceVisible } from 'react-lazyload'
|
||||
|
||||
const Gallery = styled.div`
|
||||
display: flex;
|
||||
|
@ -26,6 +27,10 @@ const PhotoFiller = styled.div`
|
|||
flex-grow: 999999;
|
||||
`
|
||||
|
||||
const ClearWrap = styled.div`
|
||||
clear: both;
|
||||
`
|
||||
|
||||
const PhotoGallery = ({
|
||||
activeIndex = -1,
|
||||
media,
|
||||
|
@ -35,6 +40,7 @@ const PhotoGallery = ({
|
|||
setPresenting,
|
||||
nextImage,
|
||||
previousImage,
|
||||
onFavorite,
|
||||
}) => {
|
||||
const { updateSidebar } = useContext(SidebarContext)
|
||||
|
||||
|
@ -89,6 +95,7 @@ const PhotoGallery = ({
|
|||
updateSidebar(<MediaSidebar media={photo} />)
|
||||
onSelectImage(index)
|
||||
}}
|
||||
onFavorite={onFavorite}
|
||||
setPresenting={setPresenting}
|
||||
minWidth={minWidth}
|
||||
index={index}
|
||||
|
@ -105,8 +112,12 @@ const PhotoGallery = ({
|
|||
return photoElements
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
!loading && forceVisible()
|
||||
}, [loading])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ClearWrap>
|
||||
<Gallery>
|
||||
<Loader active={loading}>Loading images</Loader>
|
||||
{getPhotoElements(updateSidebar)}
|
||||
|
@ -118,7 +129,7 @@ const PhotoGallery = ({
|
|||
{...{ nextImage, previousImage, setPresenting }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ClearWrap>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -131,6 +142,7 @@ PhotoGallery.propTypes = {
|
|||
setPresenting: PropTypes.func,
|
||||
nextImage: PropTypes.func,
|
||||
previousImage: PropTypes.func,
|
||||
onFavorite: PropTypes.func,
|
||||
}
|
||||
|
||||
export default PhotoGallery
|
||||
|
|
Loading…
Reference in New Issue