Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
E
exam_12_Tsoy_Danil
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Цой Данил
exam_12_Tsoy_Danil
Commits
bba25780
Commit
bba25780
authored
Apr 15, 2023
by
Цой Данил
💬
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added basic front to show all data
parent
e3b30264
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
897 additions
and
180 deletions
+897
-180
fixtures.ts
backend/src/fixtures.ts
+0
-5
tsconfig.json
backend/tsconfig.json
+104
-103
.env
frontend/.env
+1
-0
App.tsx
frontend/src/App.tsx
+21
-26
Header.tsx
frontend/src/components/Header/Header.tsx
+0
-42
Layout.tsx
frontend/src/components/Layout/Layout.tsx
+1
-2
IPhotoBlockProps.ts
frontend/src/components/PhotoBlock/IPhotoBlockProps.ts
+8
-0
PhotoBlock.tsx
frontend/src/components/PhotoBlock/PhotoBlock.tsx
+50
-0
IPhotoUserGalleryBlockProps.ts
...ents/PhotoUserGalleryBlock/IPhotoUserGalleryBlockProps.ts
+8
-0
PhotoUserGalleryBlock.module.css
...ts/PhotoUserGalleryBlock/PhotoUserGalleryBlock.module.css
+0
-0
PhotoUserGalleryBlock.tsx
...omponents/PhotoUserGalleryBlock/PhotoUserGalleryBlock.tsx
+53
-0
AddForm.module.css
frontend/src/containers/AddForm/AddForm.module.css
+32
-0
AddForm.tsx
frontend/src/containers/AddForm/AddForm.tsx
+112
-0
AuthorizeForm.module.css
...end/src/containers/AuthorizeForm/AuthorizeForm.module.css
+98
-0
AuthorizeForm.tsx
frontend/src/containers/AuthorizeForm/AuthorizeForm.tsx
+118
-0
ErrorPage.tsx
frontend/src/containers/ErrorPage/ErrorPage.tsx
+34
-0
MainPage.module.css
frontend/src/containers/MainPage/MainPage.module.css
+10
-0
MainPage.tsx
frontend/src/containers/MainPage/MainPage.tsx
+110
-0
UserGallery.tsx
frontend/src/containers/UserGallery/UserGallery.tsx
+135
-0
EStatuses.ts
frontend/src/enum/EStatuses.ts
+2
-2
No files found.
backend/src/fixtures.ts
View file @
bba25780
...
...
@@ -49,11 +49,6 @@ export default db.once('open', async () => {
title
:
'Commander Ledros'
,
photo
:
'ledros.jpg'
},
{
user
:
userOne
.
_id
,
title
:
'Commander Ledros'
,
photo
:
'ledros.jpg'
},
{
user
:
userTwo
.
_id
,
title
:
'Quinn and Valor'
,
...
...
backend/tsconfig.json
View file @
bba25780
{
"compilerOptions"
:
{
/*
Visit
https
:
//aka.ms/tsconfig
to
read
more
about
this
file
*/
/*
Projects
*/
//
"incremental"
:
true
,
/*
Save
.tsbuildinfo
files
to
allow
for
incremental
compilation
of
projects.
*/
//
"composite"
:
true
,
/*
Enable
constraints
that
allow
a
TypeScript
project
to
be
used
with
project
references.
*/
//
"tsBuildInfoFile"
:
"./.tsbuildinfo"
,
/*
Specify
the
path
to
.tsbuildinfo
incremental
compilation
file.
*/
//
"disableSourceOfProjectReferenceRedirect"
:
true
,
/*
Disable
preferring
source
files
instead
of
declaration
files
when
referencing
composite
projects.
*/
//
"disableSolutionSearching"
:
true
,
/*
Opt
a
project
out
of
multi-project
reference
checking
when
editing.
*/
//
"disableReferencedProjectLoad"
:
true
,
/*
Reduce
the
number
of
projects
loaded
automatically
by
TypeScript.
*/
/*
Language
and
Environment
*/
"target"
:
"es2020"
,
/*
Set
the
JavaScript
language
version
for
emitted
JavaScript
and
include
compatible
library
declarations.
*/
//
"lib"
:
[],
/*
Specify
a
set
of
bundled
library
declaration
files
that
describe
the
target
runtime
environment.
*/
//
"jsx"
:
"preserve"
,
/*
Specify
what
JSX
code
is
generated.
*/
"experimentalDecorators"
:
true
,
/*
Enable
experimental
support
for
TC
39
stage
2
draft
decorators.
*/
"emitDecoratorMetadata"
:
true
,
/*
Emit
design-type
metadata
for
decorated
declarations
in
source
files.
*/
//
"jsxFactory"
:
""
,
/*
Specify
the
JSX
factory
function
used
when
targeting
React
JSX
emit
,
e.g.
'React.createElement'
or
'h'.
*/
//
"jsxFragmentFactory"
:
""
,
/*
Specify
the
JSX
Fragment
reference
used
for
fragments
when
targeting
React
JSX
emit
e.g.
'React.Fragment'
or
'Fragment'.
*/
//
"jsxImportSource"
:
""
,
/*
Specify
module
specifier
used
to
import
the
JSX
factory
functions
when
using
'jsx
:
react-jsx*'.
*/
//
"reactNamespace"
:
""
,
/*
Specify
the
object
invoked
for
'createElement'.
This
only
applies
when
targeting
'react'
JSX
emit.
*/
//
"noLib"
:
true
,
/*
Disable
including
any
library
files
,
including
the
default
lib.d.ts.
*/
//
"useDefineForClassFields"
:
true
,
/*
Emit
ECMAScript-standard-compliant
class
fields.
*/
//
"moduleDetection"
:
"auto"
,
/*
Control
what
method
is
used
to
detect
module-format
JS
files.
*/
/*
Modules
*/
"module"
:
"NodeNext"
,
/*
Specify
what
module
code
is
generated.
*/
//
"rootDir"
:
"./"
,
/*
Specify
the
root
folder
within
your
source
files.
*/
"moduleResolution"
:
"NodeNext"
,
/*
Specify
how
TypeScript
looks
up
a
file
from
a
given
module
specifier.
*/
//
"baseUrl"
:
"./"
,
/*
Specify
the
base
directory
to
resolve
non-relative
module
names.
*/
//
"paths"
:
{},
/*
Specify
a
set
of
entries
that
re-map
imports
to
additional
lookup
locations.
*/
//
"rootDirs"
:
[],
/*
Allow
multiple
folders
to
be
treated
as
one
when
resolving
modules.
*/
//
"typeRoots"
:
[],
/*
Specify
multiple
folders
that
act
like
'./node_modules/@types'.
*/
//
"types"
:
[],
/*
Specify
type
package
names
to
be
included
without
being
referenced
in
a
source
file.
*/
//
"allowUmdGlobalAccess"
:
true
,
/*
Allow
accessing
UMD
globals
from
modules.
*/
//
"moduleSuffixes"
:
[],
/*
List
of
file
name
suffixes
to
search
when
resolving
a
module.
*/
//
"resolveJsonModule"
:
true
,
/*
Enable
importing
.json
files.
*/
//
"noResolve"
:
true
,
/*
Disallow
'import's
,
'require's
or
'<reference>'s
from
expanding
the
number
of
files
TypeScript
should
add
to
a
project.
*/
/*
JavaScript
Support
*/
//
"allowJs"
:
true
,
/*
Allow
JavaScript
files
to
be
a
part
of
your
program.
Use
the
'checkJS'
option
to
get
errors
from
these
files.
*/
//
"checkJs"
:
true
,
/*
Enable
error
reporting
in
type-checked
JavaScript
files.
*/
//
"maxNodeModuleJsDepth"
:
1
,
/*
Specify
the
maximum
folder
depth
used
for
checking
JavaScript
files
from
'node_modules'.
Only
applicable
with
'allowJs'.
*/
/*
Emit
*/
//
"declaration"
:
true
,
/*
Generate
.d.ts
files
from
TypeScript
and
JavaScript
files
in
your
project.
*/
//
"declarationMap"
:
true
,
/*
Create
sourcemaps
for
d.ts
files.
*/
//
"emitDeclarationOnly"
:
true
,
/*
Only
output
d.ts
files
and
not
JavaScript
files.
*/
//
"sourceMap"
:
true
,
/*
Create
source
map
files
for
emitted
JavaScript
files.
*/
//
"outFile"
:
"./"
,
/*
Specify
a
file
that
bundles
all
outputs
into
one
JavaScript
file.
If
'declaration'
is
true
,
also
designates
a
file
that
bundles
all
.d.ts
output.
*/
"outDir"
:
"dist"
,
/*
Specify
an
output
folder
for
all
emitted
files.
*/
//
"removeComments"
:
true
,
/*
Disable
emitting
comments.
*/
//
"noEmit"
:
true
,
/*
Disable
emitting
files
from
a
compilation.
*/
//
"importHelpers"
:
true
,
/*
Allow
importing
helper
functions
from
tslib
once
per
project
,
instead
of
including
them
per-file.
*/
//
"importsNotUsedAsValues"
:
"remove"
,
/*
Specify
emit/checking
behavior
for
imports
that
are
only
used
for
types.
*/
//
"downlevelIteration"
:
true
,
/*
Emit
more
compliant
,
but
verbose
and
less
performant
JavaScript
for
iteration.
*/
//
"sourceRoot"
:
""
,
/*
Specify
the
root
path
for
debuggers
to
find
the
reference
source
code.
*/
//
"mapRoot"
:
""
,
/*
Specify
the
location
where
debugger
should
locate
map
files
instead
of
generated
locations.
*/
//
"inlineSourceMap"
:
true
,
/*
Include
sourcemap
files
inside
the
emitted
JavaScript.
*/
//
"inlineSources"
:
true
,
/*
Include
source
code
in
the
sourcemaps
inside
the
emitted
JavaScript.
*/
//
"emitBOM"
:
true
,
/*
Emit
a
UTF
-8
Byte
Order
Mark
(BOM)
in
the
beginning
of
output
files.
*/
//
"newLine"
:
"crlf"
,
/*
Set
the
newline
character
for
emitting
files.
*/
//
"stripInternal"
:
true
,
/*
Disable
emitting
declarations
that
have
'@internal'
in
their
JSDoc
comments.
*/
//
"noEmitHelpers"
:
true
,
/*
Disable
generating
custom
helper
functions
like
'__extends'
in
compiled
output.
*/
//
"noEmitOnError"
:
true
,
/*
Disable
emitting
files
if
any
type
checking
errors
are
reported.
*/
//
"preserveConstEnums"
:
true
,
/*
Disable
erasing
'const
enum'
declarations
in
generated
code.
*/
//
"declarationDir"
:
"./"
,
/*
Specify
the
output
directory
for
generated
declaration
files.
*/
//
"preserveValueImports"
:
true
,
/*
Preserve
unused
imported
values
in
the
JavaScript
output
that
would
otherwise
be
removed.
*/
/*
Interop
Constraints
*/
//
"isolatedModules"
:
true
,
/*
Ensure
that
each
file
can
be
safely
transpiled
without
relying
on
other
imports.
*/
//
"allowSyntheticDefaultImports"
:
true
,
/*
Allow
'import
x
from
y'
when
a
module
doesn't
have
a
default
export.
*/
"esModuleInterop"
:
true
,
/*
Emit
additional
JavaScript
to
ease
support
for
importing
CommonJS
modules.
This
enables
'allowSyntheticDefaultImports'
for
type
compatibility.
*/
//
"preserveSymlinks"
:
true
,
/*
Disable
resolving
symlinks
to
their
realpath.
This
correlates
to
the
same
flag
in
node.
*/
"forceConsistentCasingInFileNames"
:
true
,
/*
Ensure
that
casing
is
correct
in
imports.
*/
/*
Type
Checking
*/
"strict"
:
true
,
/*
Enable
all
strict
type-checking
options.
*/
//
"noImplicitAny"
:
true
,
/*
Enable
error
reporting
for
expressions
and
declarations
with
an
implied
'any'
type.
*/
//
"strictNullChecks"
:
true
,
/*
When
type
checking
,
take
into
account
'
null
'
and
'undefined'.
*/
//
"strictFunctionTypes"
:
true
,
/*
When
assigning
functions
,
check
to
ensure
parameters
and
the
return
values
are
subtype-compatible.
*/
//
"strictBindCallApply"
:
true
,
/*
Check
that
the
arguments
for
'bind'
,
'call'
,
and
'apply'
methods
match
the
original
function.
*/
//
"strictPropertyInitialization"
:
true
,
/*
Check
for
class
properties
that
are
declared
but
not
set
in
the
constructor.
*/
//
"noImplicitThis"
:
true
,
/*
Enable
error
reporting
when
'this'
is
given
the
type
'any'.
*/
//
"useUnknownInCatchVariables"
:
true
,
/*
Default
catch
clause
variables
as
'unknown'
instead
of
'any'.
*/
//
"alwaysStrict"
:
true
,
/*
Ensure
'use
strict'
is
always
emitted.
*/
//
"noUnusedLocals"
:
true
,
/*
Enable
error
reporting
when
local
variables
aren't
read.
*/
//
"noUnusedParameters"
:
true
,
/*
Raise
an
error
when
a
function
parameter
isn't
read.
*/
//
"exactOptionalPropertyTypes"
:
true
,
/*
Interpret
optional
property
types
as
written
,
rather
than
adding
'undefined'.
*/
//
"noImplicitReturns"
:
true
,
/*
Enable
error
reporting
for
codepaths
that
do
not
explicitly
return
in
a
function.
*/
//
"noFallthroughCasesInSwitch"
:
true
,
/*
Enable
error
reporting
for
fallthrough
cases
in
switch
statements.
*/
//
"noUncheckedIndexedAccess"
:
true
,
/*
Add
'undefined'
to
a
type
when
accessed
using
an
index.
*/
//
"noImplicitOverride"
:
true
,
/*
Ensure
overriding
members
in
derived
classes
are
marked
with
an
override
modifier.
*/
//
"noPropertyAccessFromIndexSignature"
:
true
,
/*
Enforces
using
indexed
accessors
for
keys
declared
using
an
indexed
type.
*/
//
"allowUnusedLabels"
:
true
,
/*
Disable
error
reporting
for
unused
labels.
*/
//
"allowUnreachableCode"
:
true
,
/*
Disable
error
reporting
for
unreachable
code.
*/
/*
Completeness
*/
//
"skipDefaultLibCheck"
:
true
,
/*
Skip
type
checking
.d.ts
files
that
are
included
with
TypeScript.
*/
"skipLibCheck"
:
true
/*
Skip
type
checking
all
.d.ts
files.
*/
},
"include"
:
[
"src/**/*"
]
}
"compilerOptions"
:
{
/*
Visit
https
:
//aka.ms/tsconfig
to
read
more
about
this
file
*/
/*
Projects
*/
//
"incremental"
:
true
,
/*
Save
.tsbuildinfo
files
to
allow
for
incremental
compilation
of
projects.
*/
//
"composite"
:
true
,
/*
Enable
constraints
that
allow
a
TypeScript
project
to
be
used
with
project
references.
*/
//
"tsBuildInfoFile"
:
"./.tsbuildinfo"
,
/*
Specify
the
path
to
.tsbuildinfo
incremental
compilation
file.
*/
//
"disableSourceOfProjectReferenceRedirect"
:
true
,
/*
Disable
preferring
source
files
instead
of
declaration
files
when
referencing
composite
projects.
*/
//
"disableSolutionSearching"
:
true
,
/*
Opt
a
project
out
of
multi-project
reference
checking
when
editing.
*/
//
"disableReferencedProjectLoad"
:
true
,
/*
Reduce
the
number
of
projects
loaded
automatically
by
TypeScript.
*/
/*
Language
and
Environment
*/
"target"
:
"es2020"
,
/*
Set
the
JavaScript
language
version
for
emitted
JavaScript
and
include
compatible
library
declarations.
*/
//
"lib"
:
[],
/*
Specify
a
set
of
bundled
library
declaration
files
that
describe
the
target
runtime
environment.
*/
//
"jsx"
:
"preserve"
,
/*
Specify
what
JSX
code
is
generated.
*/
"experimentalDecorators"
:
true
,
/*
Enable
experimental
support
for
TC
39
stage
2
draft
decorators.
*/
"emitDecoratorMetadata"
:
true
,
/*
Emit
design-type
metadata
for
decorated
declarations
in
source
files.
*/
//
"jsxFactory"
:
""
,
/*
Specify
the
JSX
factory
function
used
when
targeting
React
JSX
emit
,
e.g.
'React.createElement'
or
'h'.
*/
//
"jsxFragmentFactory"
:
""
,
/*
Specify
the
JSX
Fragment
reference
used
for
fragments
when
targeting
React
JSX
emit
e.g.
'React.Fragment'
or
'Fragment'.
*/
//
"jsxImportSource"
:
""
,
/*
Specify
module
specifier
used
to
import
the
JSX
factory
functions
when
using
'jsx
:
react-jsx*'.
*/
//
"reactNamespace"
:
""
,
/*
Specify
the
object
invoked
for
'createElement'.
This
only
applies
when
targeting
'react'
JSX
emit.
*/
//
"noLib"
:
true
,
/*
Disable
including
any
library
files
,
including
the
default
lib.d.ts.
*/
//
"useDefineForClassFields"
:
true
,
/*
Emit
ECMAScript-standard-compliant
class
fields.
*/
//
"moduleDetection"
:
"auto"
,
/*
Control
what
method
is
used
to
detect
module-format
JS
files.
*/
/*
Modules
*/
"module"
:
"NodeNext"
,
/*
Specify
what
module
code
is
generated.
*/
//
"rootDir"
:
"./"
,
/*
Specify
the
root
folder
within
your
source
files.
*/
"moduleResolution"
:
"NodeNext"
,
/*
Specify
how
TypeScript
looks
up
a
file
from
a
given
module
specifier.
*/
//
"baseUrl"
:
"./"
,
/*
Specify
the
base
directory
to
resolve
non-relative
module
names.
*/
//
"paths"
:
{},
/*
Specify
a
set
of
entries
that
re-map
imports
to
additional
lookup
locations.
*/
//
"rootDirs"
:
[],
/*
Allow
multiple
folders
to
be
treated
as
one
when
resolving
modules.
*/
//
"typeRoots"
:
[],
/*
Specify
multiple
folders
that
act
like
'./node_modules/@types'.
*/
//
"types"
:
[],
/*
Specify
type
package
names
to
be
included
without
being
referenced
in
a
source
file.
*/
//
"allowUmdGlobalAccess"
:
true
,
/*
Allow
accessing
UMD
globals
from
modules.
*/
//
"moduleSuffixes"
:
[],
/*
List
of
file
name
suffixes
to
search
when
resolving
a
module.
*/
//
"resolveJsonModule"
:
true
,
/*
Enable
importing
.json
files.
*/
//
"noResolve"
:
true
,
/*
Disallow
'import's
,
'require's
or
'<reference>'s
from
expanding
the
number
of
files
TypeScript
should
add
to
a
project.
*/
/*
JavaScript
Support
*/
//
"allowJs"
:
true
,
/*
Allow
JavaScript
files
to
be
a
part
of
your
program.
Use
the
'checkJS'
option
to
get
errors
from
these
files.
*/
//
"checkJs"
:
true
,
/*
Enable
error
reporting
in
type-checked
JavaScript
files.
*/
//
"maxNodeModuleJsDepth"
:
1
,
/*
Specify
the
maximum
folder
depth
used
for
checking
JavaScript
files
from
'node_modules'.
Only
applicable
with
'allowJs'.
*/
/*
Emit
*/
//
"declaration"
:
true
,
/*
Generate
.d.ts
files
from
TypeScript
and
JavaScript
files
in
your
project.
*/
//
"declarationMap"
:
true
,
/*
Create
sourcemaps
for
d.ts
files.
*/
//
"emitDeclarationOnly"
:
true
,
/*
Only
output
d.ts
files
and
not
JavaScript
files.
*/
//
"sourceMap"
:
true
,
/*
Create
source
map
files
for
emitted
JavaScript
files.
*/
//
"outFile"
:
"./"
,
/*
Specify
a
file
that
bundles
all
outputs
into
one
JavaScript
file.
If
'declaration'
is
true
,
also
designates
a
file
that
bundles
all
.d.ts
output.
*/
"outDir"
:
"dist"
,
/*
Specify
an
output
folder
for
all
emitted
files.
*/
//
"removeComments"
:
true
,
/*
Disable
emitting
comments.
*/
//
"noEmit"
:
true
,
/*
Disable
emitting
files
from
a
compilation.
*/
//
"importHelpers"
:
true
,
/*
Allow
importing
helper
functions
from
tslib
once
per
project
,
instead
of
including
them
per-file.
*/
//
"importsNotUsedAsValues"
:
"remove"
,
/*
Specify
emit/checking
behavior
for
imports
that
are
only
used
for
types.
*/
//
"downlevelIteration"
:
true
,
/*
Emit
more
compliant
,
but
verbose
and
less
performant
JavaScript
for
iteration.
*/
//
"sourceRoot"
:
""
,
/*
Specify
the
root
path
for
debuggers
to
find
the
reference
source
code.
*/
//
"mapRoot"
:
""
,
/*
Specify
the
location
where
debugger
should
locate
map
files
instead
of
generated
locations.
*/
//
"inlineSourceMap"
:
true
,
/*
Include
sourcemap
files
inside
the
emitted
JavaScript.
*/
//
"inlineSources"
:
true
,
/*
Include
source
code
in
the
sourcemaps
inside
the
emitted
JavaScript.
*/
//
"emitBOM"
:
true
,
/*
Emit
a
UTF
-8
Byte
Order
Mark
(BOM)
in
the
beginning
of
output
files.
*/
//
"newLine"
:
"crlf"
,
/*
Set
the
newline
character
for
emitting
files.
*/
//
"stripInternal"
:
true
,
/*
Disable
emitting
declarations
that
have
'@internal'
in
their
JSDoc
comments.
*/
//
"noEmitHelpers"
:
true
,
/*
Disable
generating
custom
helper
functions
like
'__extends'
in
compiled
output.
*/
//
"noEmitOnError"
:
true
,
/*
Disable
emitting
files
if
any
type
checking
errors
are
reported.
*/
//
"preserveConstEnums"
:
true
,
/*
Disable
erasing
'const
enum'
declarations
in
generated
code.
*/
//
"declarationDir"
:
"./"
,
/*
Specify
the
output
directory
for
generated
declaration
files.
*/
//
"preserveValueImports"
:
true
,
/*
Preserve
unused
imported
values
in
the
JavaScript
output
that
would
otherwise
be
removed.
*/
/*
Interop
Constraints
*/
//
"isolatedModules"
:
true
,
/*
Ensure
that
each
file
can
be
safely
transpiled
without
relying
on
other
imports.
*/
//
"allowSyntheticDefaultImports"
:
true
,
/*
Allow
'import
x
from
y'
when
a
module
doesn't
have
a
default
export.
*/
"esModuleInterop"
:
true
,
/*
Emit
additional
JavaScript
to
ease
support
for
importing
CommonJS
modules.
This
enables
'allowSyntheticDefaultImports'
for
type
compatibility.
*/
//
"preserveSymlinks"
:
true
,
/*
Disable
resolving
symlinks
to
their
realpath.
This
correlates
to
the
same
flag
in
node.
*/
"forceConsistentCasingInFileNames"
:
true
,
/*
Ensure
that
casing
is
correct
in
imports.
*/
/*
Type
Checking
*/
"strict"
:
true
,
/*
Enable
all
strict
type-checking
options.
*/
//
"noImplicitAny"
:
true
,
/*
Enable
error
reporting
for
expressions
and
declarations
with
an
implied
'any'
type.
*/
//
"strictNullChecks"
:
true
,
/*
When
type
checking
,
take
into
account
'
null
'
and
'undefined'.
*/
//
"strictFunctionTypes"
:
true
,
/*
When
assigning
functions
,
check
to
ensure
parameters
and
the
return
values
are
subtype-compatible.
*/
//
"strictBindCallApply"
:
true
,
/*
Check
that
the
arguments
for
'bind'
,
'call'
,
and
'apply'
methods
match
the
original
function.
*/
//
"strictPropertyInitialization"
:
true
,
/*
Check
for
class
properties
that
are
declared
but
not
set
in
the
constructor.
*/
//
"noImplicitThis"
:
true
,
/*
Enable
error
reporting
when
'this'
is
given
the
type
'any'.
*/
//
"useUnknownInCatchVariables"
:
true
,
/*
Default
catch
clause
variables
as
'unknown'
instead
of
'any'.
*/
//
"alwaysStrict"
:
true
,
/*
Ensure
'use
strict'
is
always
emitted.
*/
//
"noUnusedLocals"
:
true
,
/*
Enable
error
reporting
when
local
variables
aren't
read.
*/
//
"noUnusedParameters"
:
true
,
/*
Raise
an
error
when
a
function
parameter
isn't
read.
*/
//
"exactOptionalPropertyTypes"
:
true
,
/*
Interpret
optional
property
types
as
written
,
rather
than
adding
'undefined'.
*/
//
"noImplicitReturns"
:
true
,
/*
Enable
error
reporting
for
codepaths
that
do
not
explicitly
return
in
a
function.
*/
//
"noFallthroughCasesInSwitch"
:
true
,
/*
Enable
error
reporting
for
fallthrough
cases
in
switch
statements.
*/
//
"noUncheckedIndexedAccess"
:
true
,
/*
Add
'undefined'
to
a
type
when
accessed
using
an
index.
*/
//
"noImplicitOverride"
:
true
,
/*
Ensure
overriding
members
in
derived
classes
are
marked
with
an
override
modifier.
*/
//
"noPropertyAccessFromIndexSignature"
:
true
,
/*
Enforces
using
indexed
accessors
for
keys
declared
using
an
indexed
type.
*/
//
"allowUnusedLabels"
:
true
,
/*
Disable
error
reporting
for
unused
labels.
*/
//
"allowUnreachableCode"
:
true
,
/*
Disable
error
reporting
for
unreachable
code.
*/
/*
Completeness
*/
//
"skipDefaultLibCheck"
:
true
,
/*
Skip
type
checking
.d.ts
files
that
are
included
with
TypeScript.
*/
"skipLibCheck"
:
true
/*
Skip
type
checking
all
.d.ts
files.
*/
},
"include"
:
[
"src/**/*"
]
}
\ No newline at end of file
frontend/.env
0 → 100644
View file @
bba25780
VITE_BASE_URL=http://localhost:8000/
\ No newline at end of file
frontend/src/App.tsx
View file @
bba25780
import
{
useState
}
from
'react'
import
React
,
{
useState
}
from
'react'
import
reactLogo
from
'./assets/react.svg'
import
viteLogo
from
'/vite.svg'
import
'./App.css'
import
{
Route
,
Routes
}
from
'react-router-dom'
import
Layout
from
'./components/Layout/Layout'
import
PrivateRoute
from
'./utils/PrivateRoute'
import
ErrorPage
from
'./containers/ErrorPage/ErrorPage'
import
AuthorizeForm
from
'./containers/AuthorizeForm/AuthorizeForm'
import
MainPage
from
'./containers/MainPage/MainPage'
import
UserGallery
from
'./containers/UserGallery/UserGallery'
import
AddForm
from
'./containers/AddForm/AddForm'
function
App
()
{
const
[
count
,
setCount
]
=
useState
(
0
)
const
App
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
return
(
<
div
className=
"App"
>
<
div
>
<
a
href=
"https://vitejs.dev"
target=
"_blank"
>
<
img
src=
{
viteLogo
}
className=
"logo"
alt=
"Vite logo"
/>
</
a
>
<
a
href=
"https://reactjs.org"
target=
"_blank"
>
<
img
src=
{
reactLogo
}
className=
"logo react"
alt=
"React logo"
/>
</
a
>
</
div
>
<
h1
>
Vite + React
</
h1
>
<
div
className=
"card"
>
<
button
onClick=
{
()
=>
setCount
((
count
)
=>
count
+
1
)
}
>
count is
{
count
}
</
button
>
<
p
>
Edit
<
code
>
src/App.tsx
</
code
>
and save to test HMR
</
p
>
</
div
>
<
p
className=
"read-the-docs"
>
Click on the Vite and React logos to learn more
</
p
>
</
div
>
<
Routes
>
<
Route
element=
{
<
Layout
/>
}
>
<
Route
path=
'/'
element=
{
<
MainPage
/>
}
/>
<
Route
path=
'/user/:id'
element=
{
<
UserGallery
/>
}
/>
<
Route
path=
'/authorize'
element=
{
<
AuthorizeForm
/>
}
/>
<
Route
element=
{
<
PrivateRoute
/>
}
>
<
Route
path=
'/add-photo'
element=
{
<
AddForm
/>
}
/>
</
Route
>
<
Route
path=
'*'
element=
{
<
ErrorPage
/>
}
/>
</
Route
>
</
Routes
>
)
}
...
...
frontend/src/components/Header/Header.tsx
View file @
bba25780
...
...
@@ -71,48 +71,6 @@ const Header: React.FunctionComponent = (): React.ReactElement => {
<
h4
style=
{
{
margin
:
0
,
color
:
'black'
,
marginRight
:
'40px'
}
}
>
<
span
style=
{
{
fontWeight
:
'normal'
,
marginRight
:
'10px'
}
}
>
Hello,
</
span
><
NavLink
to=
{
`/user/${user?._id}`
}
>
{
user
?.
username
}
</
NavLink
>
</
h4
>
<
Button
ref=
{
anchorRef
}
id=
"composition-button"
aria
-
controls=
{
open
?
'composition-menu'
:
undefined
}
aria
-
expanded=
{
open
?
'true'
:
undefined
}
aria
-
haspopup=
"true"
onClick=
{
handleToggle
}
>
Navigate menu
</
Button
>
{
/* <Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
placement="bottom-start"
transition
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === 'bottom-start' ? 'left top' : 'left bottom',
}}
>
<Paper
style={{position: 'relative', zIndex: 1000, fontWeight: 'bold'}}
>
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
id="composition-menu"
aria-labelledby="composition-button"
onKeyDown={handleListKeyDown}
>
<MenuItem onClick={()=>{navigateToPage('/add-photo')}}>Add new photo</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper> */
}
<
button
className=
{
styles
.
Header_button
}
onClick=
{
logoutHandler
}
>
Logout
</
button
>
</
div
>
:
<
div
>
...
...
frontend/src/components/Layout/Layout.tsx
View file @
bba25780
import
React
from
"react"
;
import
{
Outlet
}
from
"react-router-dom"
;
import
Header
from
"../Header/Header"
;
import
styles
from
'./Layout.module.css'
const
Layout
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
return
(
<
div
className=
{
styles
.
Layout
}
>
<
div
>
<
Header
/>
<
main
>
<
Outlet
/>
...
...
frontend/src/components/PhotoBlock/IPhotoBlockProps.ts
0 → 100644
View file @
bba25780
import
{
MouseEventHandler
}
from
"react"
;
import
IPhoto
from
"../../interfaces/IPhoto"
;
export
default
interface
IPhotoBlockProps
{
photo
:
IPhoto
showFullImage
:
MouseEventHandler
<
any
>
goToUserPage
:
MouseEventHandler
<
HTMLButtonElement
>
}
\ No newline at end of file
frontend/src/components/PhotoBlock/PhotoBlock.tsx
0 → 100644
View file @
bba25780
import
*
as
React
from
'react'
;
import
Card
from
'@mui/material/Card'
;
import
CardContent
from
'@mui/material/CardContent'
;
import
CardMedia
from
'@mui/material/CardMedia'
;
import
Typography
from
'@mui/material/Typography'
;
import
{
Button
,
CardActionArea
,
CardActions
}
from
'@mui/material'
;
import
IPhotoBlockProps
from
'./IPhotoBlockProps'
;
import
image_not_found
from
'../../assets/image_not_found.png'
import
{
shallowEqual
,
useSelector
}
from
'react-redux'
;
import
{
AppState
}
from
'../../store/store'
;
const
PhotoBlock
:
React
.
FunctionComponent
<
IPhotoBlockProps
>
=
(
props
):
React
.
ReactElement
=>
{
const
{
user
}
=
useSelector
((
state
:
AppState
)
=>
state
.
users
,
shallowEqual
)
return
(
<
div
style=
{
{
margin
:
'10px'
}
}
>
<
Card
sx=
{
{
maxWidth
:
400
}
}
>
<
CardActionArea
onClick=
{
props
.
showFullImage
}
>
<
CardMedia
component=
"img"
width=
"350"
image=
{
import
.
meta
.
env
.
VITE_BASE_URL
+
'uploads/'
+
props
.
photo
.
photo
}
onError
=
{(
e
)
=
>
{
e
.
currentTarget
.
src
=
image_not_found
}
}
alt=
{
props
.
photo
.
title
+
'image'
}
/
>
<
CardContent
style=
{
{
margin
:
'5px'
,
padding
:
'5px'
,
marginBottom
:
0
}
}
>
<
Typography
gutterBottom
variant=
"h5"
component=
"div"
style=
{
{
marginBottom
:
0
}
}
>
{
props
.
photo
.
title
}
</
Typography
>
</
CardContent
>
</
CardActionArea
>
<
CardActions
>
<
Button
onClick=
{
props
.
goToUserPage
}
size=
"small"
color=
"primary"
>
{
user
?.
username
===
props
.
photo
.
user
.
username
?
'My Photo'
:
props
.
photo
.
user
.
username
}
</
Button
>
</
CardActions
>
</
Card
>
</
div
>
);
}
export default PhotoBlock
\ No newline at end of file
frontend/src/components/PhotoUserGalleryBlock/IPhotoUserGalleryBlockProps.ts
0 → 100644
View file @
bba25780
import
{
MouseEventHandler
}
from
"react"
;
import
IPhoto
from
"../../interfaces/IPhoto"
;
export
default
interface
IPhotoUserGalleryBlockProps
{
photo
:
IPhoto
showFullImage
:
MouseEventHandler
<
any
>
deletePhoto
:
MouseEventHandler
<
HTMLButtonElement
>
}
\ No newline at end of file
frontend/src/components/PhotoUserGalleryBlock/PhotoUserGalleryBlock.module.css
0 → 100644
View file @
bba25780
frontend/src/components/PhotoUserGalleryBlock/PhotoUserGalleryBlock.tsx
0 → 100644
View file @
bba25780
import
*
as
React
from
'react'
;
import
Card
from
'@mui/material/Card'
;
import
CardContent
from
'@mui/material/CardContent'
;
import
CardMedia
from
'@mui/material/CardMedia'
;
import
Typography
from
'@mui/material/Typography'
;
import
{
Button
,
CardActionArea
,
CardActions
}
from
'@mui/material'
;
import
image_not_found
from
'../../assets/image_not_found.png'
import
{
shallowEqual
,
useSelector
}
from
'react-redux'
;
import
{
AppState
}
from
'../../store/store'
;
import
IPhotoUserGalleryBlockProps
from
'./IPhotoUserGalleryBlockProps'
;
const
PhotoUserGalleryBlock
:
React
.
FunctionComponent
<
IPhotoUserGalleryBlockProps
>
=
(
props
):
React
.
ReactElement
=>
{
const
{
user
}
=
useSelector
((
state
:
AppState
)
=>
state
.
users
,
shallowEqual
)
return
(
<
div
style=
{
{
margin
:
'10px'
}
}
>
<
Card
sx=
{
{
maxWidth
:
350
}
}
>
<
CardActionArea
onClick=
{
props
.
showFullImage
}
>
<
CardMedia
component=
"img"
width=
"200"
image=
{
import
.
meta
.
env
.
VITE_BASE_URL
+
'uploads/'
+
props
.
photo
.
photo
}
onError
=
{(
e
)
=
>
{
e
.
currentTarget
.
src
=
image_not_found
}
}
alt=
{
props
.
photo
.
title
+
'image'
}
/
>
<
CardContent
style=
{
{
margin
:
'5px'
,
padding
:
'5px'
,
marginBottom
:
0
}
}
>
<
Typography
gutterBottom
variant=
"h5"
component=
"div"
style=
{
{
marginBottom
:
0
}
}
>
{
props
.
photo
.
title
}
</
Typography
>
</
CardContent
>
</
CardActionArea
>
{
user
?.
_id
===
props
.
photo
.
user
.
_id
?
<
CardActions
>
<
Button
onClick=
{
props
.
deletePhoto
}
variant=
"outlined"
color=
"error"
>
Delete
</
Button
>
</
CardActions
>
:
null
}
</
Card
>
</
div
>
);
}
export default PhotoUserGalleryBlock
\ No newline at end of file
frontend/src/containers/AddForm/AddForm.module.css
0 → 100644
View file @
bba25780
.file_input
{
color
:
white
;
border-bottom
:
1px
solid
red
;
max-width
:
200px
;
cursor
:
pointer
;
transition
:
0.2s
;
border-radius
:
5px
;
color
:
black
;
}
.file_input
:hover
{
color
:
rgb
(
255
,
255
,
255
);
background-color
:
rgb
(
0
,
0
,
0
);
color
:
white
;
}
.filename
{
background-color
:
black
;
color
:
white
;
}
.add_btn
{
max-width
:
200px
;
width
:
100%
;
height
:
50px
;
border-radius
:
7px
;
margin-top
:
35px
;
transition
:
0.2s
;
cursor
:
pointer
;
font-weight
:
bold
;
}
.add_btn
:hover
{
background
:
rgb
(
38
,
164
,
38
);
}
\ No newline at end of file
frontend/src/containers/AddForm/AddForm.tsx
0 → 100644
View file @
bba25780
import
{
shallowEqual
}
from
"react-redux"
import
{
Button
,
TextField
}
from
'@mui/material'
;
import
Box
from
'@mui/material/Box'
;
import
Modal
from
'@mui/material/Modal'
;
import
{
AppDispatch
,
AppState
,
useAppDispatch
}
from
"../../store/store"
import
{
useSelector
}
from
"react-redux"
import
Preloader
from
"../../components/UI/Preloader/Preloader"
import
{
ChangeEvent
,
FormEvent
,
useEffect
,
useState
}
from
"react"
import
IPhotoDto
from
"../../interfaces/IPhotoDto"
import
{
addPhoto
}
from
"../../store/photos/photos.slice"
import
styles
from
'./AddForm.module.css'
const
AddForm
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
const
{
loadingPhotos
}
=
useSelector
((
state
:
AppState
)
=>
state
.
photos
,
shallowEqual
)
const
[
buttonDisabled
,
setButtonDisabled
]
=
useState
<
boolean
>
(
true
)
const
[
fileName
,
setFileName
]
=
useState
<
string
>
(
''
)
const
[
photoDto
,
setPhotoDto
]
=
useState
<
IPhotoDto
>
({
title
:
''
,
photo
:
undefined
})
const
dispatch
:
AppDispatch
=
useAppDispatch
()
const
inputHandler
=
(
e
:
ChangeEvent
<
HTMLInputElement
>
):
void
=>
{
setPhotoDto
(
prevState
=>
{
return
{...
prevState
,
[
e
.
target
.
name
]:
e
.
target
.
value
}
})
}
const
inputFileHandler
=
(
e
:
ChangeEvent
<
HTMLInputElement
>
):
void
=>
{
setPhotoDto
(
prevState
=>
{
return
{...
prevState
,
photo
:
e
.
target
.
files
?
e
.
target
.
files
[
0
]
:
undefined
}
})
setFileName
(
e
.
target
.
files
&&
e
.
target
.
files
[
0
]
?
e
.
target
.
files
[
0
].
name
:
''
)
}
const
checkButton
=
()
=>
{
if
(
photoDto
.
title
.
trim
()
===
''
||
!
photoDto
.
photo
){
setButtonDisabled
(
true
)
}
else
{
setButtonDisabled
(
false
)
}
}
const
submitHandler
=
(
e
:
FormEvent
):
void
=>
{
e
.
preventDefault
()
const
formData
=
new
FormData
()
Object
.
keys
(
photoDto
).
forEach
((
key
:
string
)
=>
{
//@ts-ignore
formData
.
append
(
key
,
photoDto
[
key
])
})
dispatch
(
addPhoto
(
formData
))
setPhotoDto
({
title
:
''
,
photo
:
undefined
})
setFileName
(
''
)
}
useEffect
(()
=>
{
checkButton
()
},[
photoDto
])
return
(
<
div
>
{
loadingPhotos
?
<
Preloader
/>
:
null
}
<
h1
>
Add new photo
</
h1
>
<
form
onSubmit=
{
submitHandler
}
style=
{
{
margin
:
'10px'
,
padding
:
'20px'
,
background
:
'#e0e0e0'
,
borderRadius
:
'5px'
,
display
:
'flex'
,
flexDirection
:
'column'
}
}
>
<
TextField
id=
"outlined-basic"
label=
"Photo title"
variant=
"outlined"
style=
{
{
marginBottom
:
'20px'
}
}
value=
{
photoDto
.
title
}
name=
'title'
onChange=
{
inputHandler
}
autoComplete=
'off'
/>
<
label
style=
{
{
height
:
'auto'
,
margin
:
'10px'
,
maxWidth
:
'30%'
,
display
:
'flex'
,
flexDirection
:
'column'
}
}
>
<
input
style=
{
{
display
:
"none"
}
}
name=
{
'photo'
}
type=
"file"
placeholder=
"Image"
accept=
".png, .jpg, .jpeg"
onChange=
{
inputFileHandler
}
/>
<
h1
className=
{
styles
.
file_input
}
style=
{
{
margin
:
'0'
}
}
>
Choose file
</
h1
>
<
span
className=
{
styles
.
filename
}
>
{
fileName
}
</
span
>
</
label
>
<
button
disabled=
{
buttonDisabled
}
className=
{
styles
.
add_btn
}
>
SEND
</
button
>
</
form
>
</
div
>
)
}
export
default
AddForm
\ No newline at end of file
frontend/src/containers/AuthorizeForm/AuthorizeForm.module.css
0 → 100644
View file @
bba25780
.AuthorizeForm
{
max-width
:
600px
;
margin
:
0
auto
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
margin-top
:
100px
;
}
.AuthorizeForm
p
{
margin
:
10px
0
;
}
.AuthorizeForm
form
{
width
:
90%
;
min-height
:
300px
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
padding
:
20px
;
background
:
rgba
(
83
,
26
,
136
,
0.659
);
border-radius
:
5px
;
}
.login_input
{
width
:
80%
;
height
:
40px
;
padding
:
5px
;
border-radius
:
7px
;
border
:
none
;
margin-bottom
:
20px
;
font-family
:
'Kanit'
,
sans-serif
;
}
.toggle
{
cursor
:
pointer
;
display
:
inline-block
;
}
.toggleSwitch
{
margin-top
:
10px
;
display
:
inline-block
;
background
:
#ccc
;
border-radius
:
16px
;
width
:
58px
;
height
:
32px
;
position
:
relative
;
vertical-align
:
middle
;
transition
:
background
0.25s
;
cursor
:
pointer
;
}
.toggleSwitch
:before
,
.toggleSwitch
:after
{
content
:
""
;
}
.toggleSwitch
:before
{
display
:
block
;
background
:
linear-gradient
(
to
bottom
,
#fff
0%
,
#eee
100%
);
border-radius
:
50%
;
box-shadow
:
0
0
0
1px
rgba
(
0
,
0
,
0
,
0.25
);
width
:
24px
;
height
:
24px
;
position
:
absolute
;
top
:
4px
;
left
:
4px
;
transition
:
left
0.25s
;
}
.toggle
:hover
.toggleSwitch
:before
{
background
:
linear-gradient
(
to
bottom
,
#fff
0%
,
#fff
100%
);
box-shadow
:
0
0
0
1px
rgba
(
0
,
0
,
0
,
0.5
);
}
.toggleCheckbox
:checked
+
.toggleSwitch
{
background
:
#0d893f
;
}
.toggleCheckbox
:checked
+
.toggleSwitch
:before
{
left
:
30px
;
}
.toggleCheckbox
{
position
:
absolute
;
visibility
:
hidden
;
}
.toggleLabel
{
margin-left
:
5px
;
position
:
relative
;
top
:
2px
;
}
.login_btn
{
margin
:
0
auto
;
margin-top
:
30px
;
width
:
170px
;
height
:
50px
;
}
.login_btn
:hover
{
background-color
:
#56c080
;
border
:
none
;
}
frontend/src/containers/AuthorizeForm/AuthorizeForm.tsx
0 → 100644
View file @
bba25780
import
{
FormEvent
,
useEffect
,
useState
}
from
'react'
import
styles
from
'./AuthorizeForm.module.css'
import
IUserCreateDto
from
'../../interfaces/IUserCreateDto'
import
{
AppDispatch
,
AppState
,
useAppDispatch
}
from
'../../store/store'
import
{
useLocation
,
useNavigate
}
from
'react-router-dom'
import
{
shallowEqual
,
useSelector
}
from
'react-redux'
import
Preloader
from
'../../components/UI/Preloader/Preloader'
import
{
createUser
,
hideMessage
,
loginUser
}
from
'../../store/user/user.slice'
import
Alert
from
'@mui/material/Alert'
;
const
AuthorizeForm
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
const
navigate
=
useNavigate
()
const
dispatch
:
AppDispatch
=
useAppDispatch
()
const
{
isAuth
,
messageUser
,
loadingUser
}
=
useSelector
((
state
:
AppState
)
=>
state
.
users
,
shallowEqual
)
const
location
=
useLocation
()
const
[
userValues
,
setUserValues
]
=
useState
<
IUserCreateDto
>
({
username
:
''
,
password
:
''
})
const
[
buttonDisabled
,
setButtonDisabled
]
=
useState
<
boolean
>
(
true
)
const
[
isLoginUser
,
setIsLoginUser
]
=
useState
<
boolean
>
(
true
)
const
inputHandler
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
):
void
=>
{
setUserValues
(
prevState
=>
{
return
{...
prevState
,
[
e
.
target
.
name
]:
e
.
target
.
value
}
})
}
const
toggleChangeHandler
=
()
=>
{
setIsLoginUser
(
!
isLoginUser
)
}
const
submitHandler
=
async
(
e
:
FormEvent
)
=>
{
e
.
preventDefault
()
if
(
isLoginUser
){
await
dispatch
(
createUser
(
userValues
))
}
else
{
await
dispatch
(
loginUser
(
userValues
))
}
}
useEffect
(()
=>
{
checkButton
()
},[
userValues
])
useEffect
(()
=>
{
if
(
isAuth
){
navigate
(
location
.
state
?.
from
?
location
.
state
.
from
:
'/'
)
}
},
[
isAuth
])
const
checkButton
=
()
=>
{
if
(
userValues
.
username
.
trim
()
===
''
||
userValues
.
password
.
trim
()
===
''
){
setButtonDisabled
(
true
)
}
else
{
setButtonDisabled
(
false
)
}
}
useEffect
(()
=>
{
dispatch
(
hideMessage
())
},
[])
return
(
<
div
className=
{
styles
.
AuthorizeForm
}
>
{
loadingUser
?
<
Preloader
/>
:
null
}
<
form
onSubmit=
{
submitHandler
}
>
{
messageUser
.
trim
()
!==
''
?
<
Alert
variant=
"filled"
severity=
"error"
>
{
messageUser
}
</
Alert
>
:
null
}
<
p
>
{
isLoginUser
?
'Login user'
:
'Authorize user'
}
</
p
>
<
p
>
Username:
</
p
>
<
input
className=
{
styles
.
login_input
}
placeholder=
'username...'
name=
{
'username'
}
autoComplete=
'off'
value=
{
userValues
.
username
}
onChange=
{
inputHandler
}
/>
<
p
>
Password:
</
p
>
<
input
className=
{
styles
.
login_input
}
placeholder=
'password...'
name=
{
'password'
}
type=
'password'
autoComplete=
'off'
value=
{
userValues
.
password
}
onChange=
{
inputHandler
}
/>
<
label
style=
{
{
display
:
'flex'
,
alignItems
:
'center'
}
}
>
<
input
className=
{
styles
.
toggleCheckbox
}
type=
"checkbox"
checked=
{
isLoginUser
}
onChange=
{
toggleChangeHandler
}
/>
<
div
className=
{
styles
.
toggleSwitch
}
></
div
>
<
span
className=
{
styles
.
toggleLabel
}
>
New user?
</
span
>
</
label
>
<
button
className=
{
styles
.
login_btn
}
disabled=
{
buttonDisabled
}
>
Authorize
</
button
>
</
form
>
</
div
>
)
}
export
default
AuthorizeForm
frontend/src/containers/ErrorPage/ErrorPage.tsx
0 → 100644
View file @
bba25780
import
React
from
'react'
;
import
{
Box
,
Button
,
Typography
}
from
'@mui/material'
;
import
{
useNavigate
}
from
'react-router-dom'
;
const
ErrorPage
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
const
navigate
=
useNavigate
()
const
goToHome
=
()
=>
{
navigate
(
'/'
)
}
return
(
<
Box
sx=
{
{
display
:
'flex'
,
justifyContent
:
'center'
,
alignItems
:
'center'
,
flexDirection
:
'column'
,
minHeight
:
'100vh'
}
}
>
<
Typography
variant=
"h1"
style=
{
{
color
:
'white'
}
}
>
404
</
Typography
>
<
Typography
variant=
"h6"
style=
{
{
color
:
'white'
}
}
>
The page you’re looking for doesn’t exist.
</
Typography
>
<
Button
onClick=
{
goToHome
}
variant=
"contained"
>
Back Home
</
Button
>
</
Box
>
);
}
export
default
ErrorPage
\ No newline at end of file
frontend/src/containers/MainPage/MainPage.module.css
0 → 100644
View file @
bba25780
.main_page_container
{
max-width
:
1400px
;
width
:
100%
;
margin
:
0
auto
;
padding
:
20px
;
margin-top
:
100px
;
display
:
flex
;
justify-content
:
space-between
;
flex-wrap
:
wrap
;
}
\ No newline at end of file
frontend/src/containers/MainPage/MainPage.tsx
0 → 100644
View file @
bba25780
import
{
useEffect
,
useState
}
from
'react'
import
{
AppDispatch
,
AppState
,
useAppDispatch
}
from
'../../store/store'
import
styles
from
'./MainPage.module.css'
import
{
getAllPhotos
,
setTargetedUser
}
from
'../../store/photos/photos.slice'
import
{
shallowEqual
,
useSelector
}
from
'react-redux'
import
IPhoto
from
'../../interfaces/IPhoto'
import
PhotoBlock
from
'../../components/PhotoBlock/PhotoBlock'
import
Backdrop
from
'@mui/material/Backdrop'
;
import
Box
from
'@mui/material/Box'
;
import
Modal
from
'@mui/material/Modal'
;
import
Fade
from
'@mui/material/Fade'
;
import
{
useNavigate
}
from
'react-router-dom'
import
{
CardMedia
}
from
'@mui/material'
import
image_not_found
from
'../../assets/image_not_found.png'
import
IUser
from
'../../interfaces/IUser'
import
Preloader
from
'../../components/UI/Preloader/Preloader'
const
modalStyles
=
{
position
:
'absolute'
as
'absolute'
,
top
:
'50%'
,
left
:
'50%'
,
transform
:
'translate(-50%, -50%)'
,
width
:
700
,
bgcolor
:
'background.paper'
,
border
:
'2px solid #000'
,
boxShadow
:
24
,
p
:
1
,
};
const
MainPage
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
const
[
open
,
setOpen
]
=
useState
<
boolean
>
(
false
);
const
[
fullImageSrc
,
setFullImageSrc
]
=
useState
<
string
>
(
''
)
const
handleClose
=
()
=>
setOpen
(
false
);
const
dispatch
:
AppDispatch
=
useAppDispatch
()
const
{
photos
,
loadingPhotos
}
=
useSelector
((
state
:
AppState
)
=>
state
.
photos
,
shallowEqual
)
const
navigate
=
useNavigate
()
const
goToUserPageHandler
=
(
user
:
IUser
)
=>
{
dispatch
(
setTargetedUser
(
user
))
navigate
(
`/user/
${
user
.
_id
}
`
)
}
const
showFullImageHandler
=
(
src
:
string
)
=>
{
setFullImageSrc
(
src
)
setOpen
(
true
)
}
useEffect
(()
=>
{
dispatch
(
getAllPhotos
())
},
[])
return
(
<
div
className=
{
styles
.
main_page_container
}
>
{
loadingPhotos
?
<
Preloader
/>
:
null
}
<
Modal
aria
-
labelledby=
"transition-modal-title"
aria
-
describedby=
"transition-modal-description"
open=
{
open
}
onClose=
{
handleClose
}
closeAfterTransition
slots=
{
{
backdrop
:
Backdrop
}
}
slotProps=
{
{
backdrop
:
{
timeout
:
500
,
},
}
}
>
<
Fade
in=
{
open
}
>
<
Box
sx=
{
modalStyles
}
>
<
CardMedia
component=
"img"
style=
{
{
maxWidth
:
'100%'
,
height
:
'auto'
,
maxHeight
:
'70vh'
}
}
image=
{
import
.
meta
.
env
.
VITE_BASE_URL
+
'uploads/'
+
fullImageSrc
}
alt=
"full image"
onError
=
{(
e
)
=
>
{
e
.
currentTarget
.
src
=
image_not_found
}
}
/
>
</
Box
>
</
Fade
>
</
Modal
>
{
photos
.
length
?
photos
.
map
((
photo
:
IPhoto
)
=>
{
return
<
PhotoBlock
key=
{
photo
.
_id
}
photo=
{
photo
}
goToUserPage=
{
()
=>
{
goToUserPageHandler
(
photo
.
user
)}
}
showFullImage=
{
()
=>
{
showFullImageHandler
(
photo
.
photo
)}
}
/>
}):
<
h1
>
Gallery
is
empty
<
/h1
>
}
</
div
>
)
}
export default MainPage
\ No newline at end of file
frontend/src/containers/UserGallery/UserGallery.tsx
0 → 100644
View file @
bba25780
import
{
useEffect
,
useState
}
from
'react'
import
{
AppDispatch
,
AppState
,
useAppDispatch
}
from
'../../store/store'
import
styles
from
'./MainPage.module.css'
import
{
deletePhotoById
,
getAllPhotos
,
getPhotosByUserId
,
setTargetedUser
}
from
'../../store/photos/photos.slice'
import
{
shallowEqual
,
useSelector
}
from
'react-redux'
import
IPhoto
from
'../../interfaces/IPhoto'
import
PhotoBlock
from
'../../components/PhotoBlock/PhotoBlock'
import
Backdrop
from
'@mui/material/Backdrop'
;
import
Box
from
'@mui/material/Box'
;
import
Modal
from
'@mui/material/Modal'
;
import
Fade
from
'@mui/material/Fade'
;
import
{
useNavigate
,
useParams
}
from
'react-router-dom'
import
{
Button
,
CardMedia
}
from
'@mui/material'
import
image_not_found
from
'../../assets/image_not_found.png'
import
IUser
from
'../../interfaces/IUser'
import
PhotoUserGalleryBlock
from
'../../components/PhotoUserGalleryBlock/PhotoUserGalleryBlock'
const
modalStyles
=
{
position
:
'absolute'
as
'absolute'
,
top
:
'50%'
,
left
:
'50%'
,
transform
:
'translate(-50%, -50%)'
,
width
:
700
,
bgcolor
:
'background.paper'
,
border
:
'2px solid #000'
,
boxShadow
:
24
,
p
:
1
,
};
export
const
UserGallery
:
React
.
FunctionComponent
=
():
React
.
ReactElement
=>
{
const
[
open
,
setOpen
]
=
useState
<
boolean
>
(
false
);
const
[
fullImageSrc
,
setFullImageSrc
]
=
useState
<
string
>
(
''
)
const
handleClose
=
()
=>
setOpen
(
false
);
const
params
=
useParams
()
const
dispatch
:
AppDispatch
=
useAppDispatch
()
const
{
photosByUser
,
targetedUser
}
=
useSelector
((
state
:
AppState
)
=>
state
.
photos
,
shallowEqual
)
const
{
user
}
=
useSelector
((
state
:
AppState
)
=>
state
.
users
,
shallowEqual
)
const
navigate
=
useNavigate
()
const
showFullImageHandler
=
(
src
:
string
)
=>
{
setFullImageSrc
(
src
)
setOpen
(
true
)
}
const
deletePhotoHandler
=
(
id
:
string
)
=>
{
dispatch
(
deletePhotoById
(
id
))
}
const
goToAddForm
=
()
=>
{
navigate
(
'/add-photo'
)
}
useEffect
(()
=>
{
if
(
params
.
id
)
dispatch
(
getPhotosByUserId
(
params
.
id
))
},
[])
return
(
<
div
style=
{
{
maxWidth
:
'1400px'
,
width
:
'100%'
,
margin
:
'0 auto'
}
}
>
<
Modal
aria
-
labelledby=
"transition-modal-title"
aria
-
describedby=
"transition-modal-description"
open=
{
open
}
onClose=
{
handleClose
}
closeAfterTransition
slots=
{
{
backdrop
:
Backdrop
}
}
slotProps=
{
{
backdrop
:
{
timeout
:
500
,
},
}
}
>
<
Fade
in=
{
open
}
>
<
Box
sx=
{
modalStyles
}
>
<
CardMedia
component=
"img"
style=
{
{
maxWidth
:
'100%'
,
height
:
'auto'
,
maxHeight
:
'70vh'
}
}
image=
{
import
.
meta
.
env
.
VITE_BASE_URL
+
'uploads/'
+
fullImageSrc
}
alt=
"full image"
onError
=
{(
e
)
=
>
{
e
.
currentTarget
.
src
=
image_not_found
}
}
/
>
</
Box
>
</
Fade
>
</
Modal
>
<
div
style=
{
{
display
:
'flex'
,
justifyContent
:
'space-between'
,
alignItems
:
'center'
}
}
>
<
h1
>
{
targetedUser
.
_id
===
user
?.
_id
?
'This is your page'
:
`${targetedUser.username}'s gallery`
}
</
h1
>
{
targetedUser
.
_id
===
user
?.
_id
?
<
Button
variant=
"contained"
size=
'medium'
onClick=
{
goToAddForm
}
>
Add Photo
</
Button
>
:
null
}
</
div
>
<
div
style=
{
{
display
:
'flex'
,
justifyContent
:
'space-between'
,
flexWrap
:
'wrap'
}
}
>
{
photosByUser
&&
photosByUser
.
length
?
photosByUser
.
map
((
photo
:
IPhoto
)
=>
{
return
<
PhotoUserGalleryBlock
key=
{
photo
.
_id
}
photo=
{
photo
}
showFullImage=
{
()
=>
showFullImageHandler
(
photo
.
photo
)
}
deletePhoto=
{
()
=>
{
deletePhotoHandler
(
photo
.
_id
)}
}
/>
}):
<
h1
>
Gallery
is
empty
<
/h1
>
}
</
div
>
</
div
>
)
}
export default UserGallery
\ No newline at end of file
frontend/src/enum/EStatuses.ts
View file @
bba25780
export
enum
EStatuses
{
SUCCESS
=
'S
uccess
'
,
FAILURE
=
'F
ailure
'
SUCCESS
=
'S
UCCESS
'
,
FAILURE
=
'F
AILURE
'
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment