mirror of
https://github.com/ershisan99/instagram-client-front.git
synced 2025-12-16 12:33:26 +00:00
lesson 3
This commit is contained in:
15
.idea/git_toolbox_prj.xml
generated
Normal file
15
.idea/git_toolbox_prj.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GitToolBoxProjectSettings">
|
||||
<option name="commitMessageIssueKeyValidationOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
<option name="commitMessageValidationEnabledOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@@ -13,12 +13,18 @@
|
||||
"@it-incubator/prettier-config": "^0.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.1.1",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@reduxjs/toolkit": "^2.2.6",
|
||||
"@types/javascript-time-ago": "^2.0.8",
|
||||
"clsx": "^2.1.1",
|
||||
"javascript-time-ago": "^2.5.10",
|
||||
"next": "14.2.5",
|
||||
"next-redux-wrapper": "^8.1.0",
|
||||
"prettier": "^3.3.2",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "7.52.1",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-time-ago": "^7.3.3",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
161
pnpm-lock.yaml
generated
161
pnpm-lock.yaml
generated
@@ -20,12 +20,24 @@ importers:
|
||||
'@radix-ui/react-icons':
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0(react@18.3.1)
|
||||
'@reduxjs/toolkit':
|
||||
specifier: ^2.2.6
|
||||
version: 2.2.6(react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1))(react@18.3.1)
|
||||
'@types/javascript-time-ago':
|
||||
specifier: ^2.0.8
|
||||
version: 2.0.8
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
javascript-time-ago:
|
||||
specifier: ^2.5.10
|
||||
version: 2.5.10
|
||||
next:
|
||||
specifier: 14.2.5
|
||||
version: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
next-redux-wrapper:
|
||||
specifier: ^8.1.0
|
||||
version: 8.1.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1))(react@18.3.1)
|
||||
prettier:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
@@ -38,6 +50,12 @@ importers:
|
||||
react-hook-form:
|
||||
specifier: 7.52.1
|
||||
version: 7.52.1(react@18.3.1)
|
||||
react-redux:
|
||||
specifier: ^9.1.2
|
||||
version: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
|
||||
react-time-ago:
|
||||
specifier: ^7.3.3
|
||||
version: 7.3.3(javascript-time-ago@2.5.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
zod:
|
||||
specifier: ^3.23.8
|
||||
version: 3.23.8
|
||||
@@ -329,6 +347,17 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@reduxjs/toolkit@2.2.6':
|
||||
resolution: {integrity: sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==}
|
||||
peerDependencies:
|
||||
react: ^16.9.0 || ^17.0.0 || ^18
|
||||
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
react-redux:
|
||||
optional: true
|
||||
|
||||
'@rushstack/eslint-patch@1.10.3':
|
||||
resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
|
||||
|
||||
@@ -338,6 +367,9 @@ packages:
|
||||
'@swc/helpers@0.5.5':
|
||||
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
||||
|
||||
'@types/javascript-time-ago@2.0.8':
|
||||
resolution: {integrity: sha512-X77q3xUzWVn0qohgurKE1G5NiXZjee8VbLqaukW/HXVkz7bdCFJgOPQ3JVB4IkrDhMS4CviFTmpZuNVg0i2QFA==}
|
||||
|
||||
'@types/json5@0.0.29':
|
||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||
|
||||
@@ -353,6 +385,9 @@ packages:
|
||||
'@types/react@18.3.3':
|
||||
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
|
||||
|
||||
'@types/use-sync-external-store@0.0.3':
|
||||
resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==}
|
||||
|
||||
'@typescript-eslint/parser@7.2.0':
|
||||
resolution: {integrity: sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==}
|
||||
engines: {node: ^16.0.0 || >=18.0.0}
|
||||
@@ -922,6 +957,9 @@ packages:
|
||||
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
immer@10.1.1:
|
||||
resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -1070,6 +1108,9 @@ packages:
|
||||
jackspeak@3.4.3:
|
||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||
|
||||
javascript-time-ago@2.5.10:
|
||||
resolution: {integrity: sha512-EUxp4BP74QH8xiYHyeSHopx1XhMMJ9qEX4rcBdFtpVWmKRdzpxbNzz2GSbuekZr5wt0rmLehuyp0PE34EAJT9g==}
|
||||
|
||||
jiti@1.21.6:
|
||||
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
|
||||
hasBin: true
|
||||
@@ -1137,6 +1178,9 @@ packages:
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
memoize-one@6.0.0:
|
||||
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -1180,6 +1224,13 @@ packages:
|
||||
natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
||||
next-redux-wrapper@8.1.0:
|
||||
resolution: {integrity: sha512-2hIau0hcI6uQszOtrvAFqgc0NkZegKYhBB7ZAKiG3jk7zfuQb4E7OV9jfxViqqojh3SEHdnFfPkN9KErttUKuw==}
|
||||
peerDependencies:
|
||||
next: '>=9'
|
||||
react: '*'
|
||||
react-redux: '*'
|
||||
|
||||
next@14.2.5:
|
||||
resolution: {integrity: sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==}
|
||||
engines: {node: '>=18.17.0'}
|
||||
@@ -1291,6 +1342,9 @@ packages:
|
||||
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
performance-now@2.1.0:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||
|
||||
picocolors@1.0.1:
|
||||
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
|
||||
|
||||
@@ -1379,6 +1433,9 @@ packages:
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
raf@3.4.1:
|
||||
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
|
||||
|
||||
react-dom@18.3.1:
|
||||
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
|
||||
peerDependencies:
|
||||
@@ -1393,6 +1450,25 @@ packages:
|
||||
react-is@16.13.1:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
|
||||
react-redux@9.1.2:
|
||||
resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==}
|
||||
peerDependencies:
|
||||
'@types/react': ^18.2.25
|
||||
react: ^18.0
|
||||
redux: ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
redux:
|
||||
optional: true
|
||||
|
||||
react-time-ago@7.3.3:
|
||||
resolution: {integrity: sha512-5kh2Kuu/UhHzcZrGvf3GUrF2d+IXjkIXif5MR2iDWIfSqQuBW27/ejN/tmzJBRyPiryYTgbDIG6AZFJ4RW3yfw==}
|
||||
peerDependencies:
|
||||
javascript-time-ago: ^2.3.7
|
||||
react: '>=0.16.8'
|
||||
react-dom: '>=0.16.8'
|
||||
|
||||
react@18.3.1:
|
||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1404,6 +1480,14 @@ packages:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
|
||||
redux-thunk@3.1.0:
|
||||
resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
|
||||
peerDependencies:
|
||||
redux: ^5.0.0
|
||||
|
||||
redux@5.0.1:
|
||||
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
|
||||
|
||||
reflect.getprototypeof@1.0.6:
|
||||
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1412,6 +1496,12 @@ packages:
|
||||
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
relative-time-format@1.1.6:
|
||||
resolution: {integrity: sha512-aCv3juQw4hT1/P/OrVltKWLlp15eW1GRcwP1XdxHrPdZE9MtgqFpegjnTjLhi2m2WI9MT/hQQtE+tjEWG1hgkQ==}
|
||||
|
||||
reselect@5.1.1:
|
||||
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
|
||||
|
||||
resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -1643,6 +1733,11 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
use-sync-external-store@1.2.2:
|
||||
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
@@ -1906,6 +2001,16 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
|
||||
'@reduxjs/toolkit@2.2.6(react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
immer: 10.1.1
|
||||
redux: 5.0.1
|
||||
redux-thunk: 3.1.0(redux@5.0.1)
|
||||
reselect: 5.1.1
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
react-redux: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
|
||||
|
||||
'@rushstack/eslint-patch@1.10.3': {}
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
@@ -1915,6 +2020,8 @@ snapshots:
|
||||
'@swc/counter': 0.1.3
|
||||
tslib: 2.6.3
|
||||
|
||||
'@types/javascript-time-ago@2.0.8': {}
|
||||
|
||||
'@types/json5@0.0.29': {}
|
||||
|
||||
'@types/node@20.14.10':
|
||||
@@ -1932,6 +2039,8 @@ snapshots:
|
||||
'@types/prop-types': 15.7.12
|
||||
csstype: 3.1.3
|
||||
|
||||
'@types/use-sync-external-store@0.0.3': {}
|
||||
|
||||
'@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 7.2.0
|
||||
@@ -2729,6 +2838,8 @@ snapshots:
|
||||
|
||||
ignore@5.3.1: {}
|
||||
|
||||
immer@10.1.1: {}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
@@ -2876,6 +2987,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
javascript-time-ago@2.5.10:
|
||||
dependencies:
|
||||
relative-time-format: 1.1.6
|
||||
|
||||
jiti@1.21.6: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
@@ -2934,6 +3049,8 @@ snapshots:
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
memoize-one@6.0.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
micromatch@4.0.7:
|
||||
@@ -2971,6 +3088,12 @@ snapshots:
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
next-redux-wrapper@8.1.0(next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1))(react@18.3.1):
|
||||
dependencies:
|
||||
next: 14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-redux: 9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1)
|
||||
|
||||
next@14.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@next/env': 14.2.5
|
||||
@@ -3091,6 +3214,8 @@ snapshots:
|
||||
|
||||
path-type@4.0.0: {}
|
||||
|
||||
performance-now@2.1.0: {}
|
||||
|
||||
picocolors@1.0.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
@@ -3160,6 +3285,10 @@ snapshots:
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
raf@3.4.1:
|
||||
dependencies:
|
||||
performance-now: 2.1.0
|
||||
|
||||
react-dom@18.3.1(react@18.3.1):
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
@@ -3172,6 +3301,24 @@ snapshots:
|
||||
|
||||
react-is@16.13.1: {}
|
||||
|
||||
react-redux@9.1.2(@types/react@18.3.3)(react@18.3.1)(redux@5.0.1):
|
||||
dependencies:
|
||||
'@types/use-sync-external-store': 0.0.3
|
||||
react: 18.3.1
|
||||
use-sync-external-store: 1.2.2(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.3
|
||||
redux: 5.0.1
|
||||
|
||||
react-time-ago@7.3.3(javascript-time-ago@2.5.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
javascript-time-ago: 2.5.10
|
||||
memoize-one: 6.0.0
|
||||
prop-types: 15.8.1
|
||||
raf: 3.4.1
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
react@18.3.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
@@ -3184,6 +3331,12 @@ snapshots:
|
||||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
|
||||
redux-thunk@3.1.0(redux@5.0.1):
|
||||
dependencies:
|
||||
redux: 5.0.1
|
||||
|
||||
redux@5.0.1: {}
|
||||
|
||||
reflect.getprototypeof@1.0.6:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
@@ -3201,6 +3354,10 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
set-function-name: 2.0.2
|
||||
|
||||
relative-time-format@1.1.6: {}
|
||||
|
||||
reselect@5.1.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
@@ -3484,6 +3641,10 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
use-sync-external-store@1.2.2(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
which-boxed-primitive@1.0.2:
|
||||
|
||||
92
src/components/loader/loader.module.css
Normal file
92
src/components/loader/loader.module.css
Normal file
@@ -0,0 +1,92 @@
|
||||
.loader {
|
||||
position: relative;
|
||||
width: 130px;
|
||||
height: 100px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: linear-gradient(#0277bd, #0277bd), linear-gradient(#29b6f6, #4fc3f7),
|
||||
linear-gradient(#29b6f6, #4fc3f7);
|
||||
background-size:
|
||||
80px 70px,
|
||||
30px 50px,
|
||||
30px 30px;
|
||||
background-position:
|
||||
0 0,
|
||||
80px 20px,
|
||||
100px 40px;
|
||||
}
|
||||
.loader:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 12px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
box-sizing: content-box;
|
||||
border: 10px solid #000;
|
||||
box-shadow:
|
||||
78px 0 0 -10px #fff,
|
||||
78px 0 #000;
|
||||
animation: wheelSk 0.75s ease-in infinite alternate;
|
||||
}
|
||||
|
||||
.loader:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
top: 0px;
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
background-image: linear-gradient(#fff 45px, transparent 0),
|
||||
linear-gradient(#fff 45px, transparent 0), linear-gradient(#fff 45px, transparent 0);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 30px 4px;
|
||||
background-position:
|
||||
0px 11px,
|
||||
8px 35px,
|
||||
0px 60px;
|
||||
animation: lineDropping 0.75s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes wheelSk {
|
||||
0%,
|
||||
50%,
|
||||
100% {
|
||||
transform: translatey(0);
|
||||
}
|
||||
30%,
|
||||
90% {
|
||||
transform: translatey(-3px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes lineDropping {
|
||||
0% {
|
||||
background-position:
|
||||
100px 11px,
|
||||
115px 35px,
|
||||
105px 60px;
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
background-position:
|
||||
0px 11px,
|
||||
20px 35px,
|
||||
5px 60px;
|
||||
}
|
||||
60% {
|
||||
background-position:
|
||||
-30px 11px,
|
||||
0px 35px,
|
||||
-10px 60px;
|
||||
}
|
||||
75%,
|
||||
100% {
|
||||
background-position:
|
||||
-30px 11px,
|
||||
-30px 35px,
|
||||
-30px 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
5
src/components/loader/loader.tsx
Normal file
5
src/components/loader/loader.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import s from './loader.module.css'
|
||||
|
||||
export const Loader = () => {
|
||||
return <span className={s.loader}></span>
|
||||
}
|
||||
@@ -1,11 +1,21 @@
|
||||
import '@/styles/globals.css'
|
||||
import type { AppProps } from 'next/app'
|
||||
import { wrapper } from '@/store'
|
||||
import { Provider } from 'react-redux'
|
||||
import TimeAgo from 'javascript-time-ago'
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
import en from 'javascript-time-ago/locale/en'
|
||||
|
||||
TimeAgo.addDefaultLocale(en)
|
||||
|
||||
export default function App({ Component, ...rest }: AppProps) {
|
||||
const { store, props } = wrapper.useWrappedStore(rest)
|
||||
return (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
<Provider store={store}>
|
||||
<Layout>
|
||||
<Component {...props.pageProps} />
|
||||
</Layout>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import Head from 'next/head'
|
||||
import Link from 'next/link'
|
||||
import ReactTimeAgo from 'react-time-ago'
|
||||
import { Loader } from '@/components/loader/loader'
|
||||
import { useState } from 'react'
|
||||
import { useGetPublicPostsQuery } from '@/services/inctagram.public-posts.service'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@@ -13,11 +17,54 @@ export default function Home() {
|
||||
}
|
||||
|
||||
function Content() {
|
||||
const [pageSize, setPageSize] = useState(4)
|
||||
const { data, isLoading, isError, error } = useGetPublicPostsQuery({
|
||||
pageSize,
|
||||
})
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={'w-screen h-screen grid place-items-center'}>
|
||||
<Loader />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return <div>Error: {JSON.stringify(error, null, 2)}</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<nav>
|
||||
<Link href={'/auth/login'}>Login</Link>
|
||||
</nav>
|
||||
<select value={pageSize} onChange={e => setPageSize(Number.parseInt(e.target.value, 10))}>
|
||||
<option value={4}>4</option>
|
||||
<option value={10}>10</option>
|
||||
<option value={15}>15</option>
|
||||
<option value={20}>20</option>
|
||||
</select>
|
||||
<div className={'grid grid-cols-4 p-6 mx-auto gap-4'}>
|
||||
{data?.items?.map(post => {
|
||||
return (
|
||||
<div key={post.id} className={'w-60'}>
|
||||
<img src={post.images[0].url} className={'w-full aspect-square object-cover'} />
|
||||
<div className={'flex gap-3 items-center mt-3'}>
|
||||
<img
|
||||
src={post.avatarOwner ?? 'https://picsum.photos/200'}
|
||||
className={'size-9 rounded-full object-cover'}
|
||||
/>
|
||||
<div>{post.userName}</div>
|
||||
</div>
|
||||
<ReactTimeAgo
|
||||
date={new Date(post.createdAt)}
|
||||
className={'mt-3 text-sm text-gray-500'}
|
||||
/>
|
||||
{post.description && <div className={'mt-4'}>{post.description}</div>}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
72
src/pages/profile.tsx
Normal file
72
src/pages/profile.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
useLazyGetUserProfileQuery,
|
||||
useUpdateUserProfileMutation,
|
||||
} from '@/services/inctagram.profile.service'
|
||||
import { FormInput } from '@/form/form-input'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { UpdateUserProfileArgs } from '@/services/inctagram.types'
|
||||
import { useUploadImageMutation } from '@/services/inctagram.service'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function Profile() {
|
||||
const [getProfile, profile] = useLazyGetUserProfileQuery()
|
||||
const [files, setFiles] = useState<FileList | null>(null)
|
||||
const [mutate, { isLoading }] = useUpdateUserProfileMutation()
|
||||
const [uploadImage, { isLoading: loadingImage }] = useUploadImageMutation()
|
||||
const { control, handleSubmit } = useForm<UpdateUserProfileArgs>({
|
||||
defaultValues: async () => {
|
||||
const { data } = await getProfile()
|
||||
|
||||
if (!data) {
|
||||
return {} as UpdateUserProfileArgs
|
||||
}
|
||||
|
||||
return {
|
||||
...data,
|
||||
firstName: data.firstName ?? '',
|
||||
lastName: data.lastName ?? '',
|
||||
dateOfBirth: '1961-07-13T17:58:17.000Z',
|
||||
aboutMe: 'HELLO BITHCHES',
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// const onSubmit = handleSubmit(data => {
|
||||
// mutate(data)
|
||||
// })
|
||||
const onSubmit = handleSubmit(mutate)
|
||||
return (
|
||||
<div>
|
||||
Profile
|
||||
<h1 className={'text-xl font-medium'}>{profile.data?.userName}</h1>
|
||||
<h2 className={'text-lg font-medium'}>
|
||||
{profile.data?.firstName} {profile.data?.lastName}
|
||||
</h2>
|
||||
<form onSubmit={onSubmit}>
|
||||
<FormInput name={'userName'} control={control} label={'User name'} />
|
||||
<FormInput name={'firstName'} control={control} label={'First name'} />
|
||||
<FormInput name={'lastName'} control={control} label={'Last name'} />
|
||||
<button disabled={isLoading}>Update profile</button>
|
||||
</form>
|
||||
<form
|
||||
onSubmit={e => {
|
||||
e.preventDefault()
|
||||
if (!files || !files.length) {
|
||||
return
|
||||
}
|
||||
uploadImage({ files })
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
name="file"
|
||||
multiple
|
||||
onChange={e => {
|
||||
setFiles(e.currentTarget.files)
|
||||
}}
|
||||
/>
|
||||
<button disabled={loadingImage}>upload image</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
27
src/services/inctagram.profile.service.ts
Normal file
27
src/services/inctagram.profile.service.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { inctagramService } from '@/services/inctagram.service'
|
||||
import { GetUserProfileResponse, UpdateUserProfileArgs } from '@/services/inctagram.types'
|
||||
|
||||
export const inctagramProfileService = inctagramService.injectEndpoints({
|
||||
endpoints: builder => {
|
||||
return {
|
||||
getUserProfile: builder.query<GetUserProfileResponse, void>({
|
||||
query: () => {
|
||||
return 'v1/users/profile'
|
||||
},
|
||||
providesTags: ['UserProfile'],
|
||||
}),
|
||||
updateUserProfile: builder.mutation<any, UpdateUserProfileArgs>({
|
||||
query: body => {
|
||||
return {
|
||||
url: '/v1/users/profile',
|
||||
method: 'PUT',
|
||||
body,
|
||||
}
|
||||
},
|
||||
invalidatesTags: ['UserProfile'],
|
||||
}),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const { useLazyGetUserProfileQuery, useUpdateUserProfileMutation } = inctagramProfileService
|
||||
29
src/services/inctagram.public-posts.service.ts
Normal file
29
src/services/inctagram.public-posts.service.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { inctagramService } from '@/services/inctagram.service'
|
||||
import {
|
||||
GetPostsArgs,
|
||||
GetPostsResponse,
|
||||
GetUserProfileResponse,
|
||||
UpdateUserProfileArgs,
|
||||
} from '@/services/inctagram.types'
|
||||
|
||||
export const inctagramPublicPostsService = inctagramService.injectEndpoints({
|
||||
endpoints: builder => {
|
||||
return {
|
||||
getPublicPosts: builder.query<GetPostsResponse, GetPostsArgs>({
|
||||
query: ({ pageSize }) => {
|
||||
return {
|
||||
url: `v1/public-posts/all/`,
|
||||
params: {
|
||||
pageSize,
|
||||
sortBy: 'createdAt',
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
}
|
||||
},
|
||||
providesTags: ['PublicPosts'],
|
||||
}),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const { useGetPublicPostsQuery } = inctagramPublicPostsService
|
||||
44
src/services/inctagram.service.ts
Normal file
44
src/services/inctagram.service.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
const token =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjczNSwiaWF0IjoxNzIxNDE0NTgzLCJleHAiOjE3MjE0MTgxODN9.O1Kao-oNtMDNtCPU0-exGlif7YJegpIVPxeZm1KC758'
|
||||
|
||||
export const inctagramService = createApi({
|
||||
// keepUnusedDataFor: 0,
|
||||
tagTypes: ['UserProfile', 'PublicPosts'],
|
||||
reducerPath: 'inctagramService',
|
||||
baseQuery: fetchBaseQuery({
|
||||
baseUrl: 'https://inctagram.work/api',
|
||||
prepareHeaders: headers => {
|
||||
headers.set('Authorization', `Bearer ${token}`)
|
||||
return headers
|
||||
},
|
||||
}),
|
||||
endpoints: builder => ({
|
||||
uploadImage: builder.mutation<any, { files: FileList }>({
|
||||
query({ files }) {
|
||||
const formData = new FormData()
|
||||
Array.from(files).forEach(file => {
|
||||
formData.append('file', file)
|
||||
})
|
||||
console.log(formData)
|
||||
return {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
url: '/v1/posts/image',
|
||||
}
|
||||
},
|
||||
}),
|
||||
deleteImage: builder.mutation<any, { id: string }>({
|
||||
query({ id }) {
|
||||
return {
|
||||
method: 'DELETE',
|
||||
url: `/v1/posts/image/${id}`,
|
||||
params: {},
|
||||
}
|
||||
},
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useUploadImageMutation } = inctagramService
|
||||
60
src/services/inctagram.types.ts
Normal file
60
src/services/inctagram.types.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
export interface GetPostsResponse {
|
||||
totalCount: number
|
||||
pageSize: number
|
||||
items: Item[]
|
||||
totalUsers: number
|
||||
}
|
||||
|
||||
export interface GetPostsArgs {
|
||||
pageSize: number
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
id: number
|
||||
userName: string
|
||||
description: string
|
||||
location?: any
|
||||
images: Image[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
avatarOwner?: string
|
||||
ownerId: number
|
||||
owner: Owner
|
||||
likesCount: number
|
||||
isLiked: boolean
|
||||
}
|
||||
|
||||
export interface Owner {
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
}
|
||||
|
||||
export interface Image {
|
||||
url: string
|
||||
width: number
|
||||
height: number
|
||||
fileSize: number
|
||||
createdAt: string
|
||||
uploadId: string
|
||||
}
|
||||
|
||||
export interface GetUserProfileResponse {
|
||||
id: number
|
||||
userName: string
|
||||
firstName?: any
|
||||
lastName?: any
|
||||
city?: any
|
||||
dateOfBirth?: any
|
||||
aboutMe?: any
|
||||
createdAt: string
|
||||
avatars: any[]
|
||||
}
|
||||
|
||||
export interface UpdateUserProfileArgs {
|
||||
userName: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
city?: string
|
||||
dateOfBirth?: string
|
||||
aboutMe?: string
|
||||
}
|
||||
23
src/store.ts
Normal file
23
src/store.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Action, configureStore, ThunkAction } from '@reduxjs/toolkit'
|
||||
import { createWrapper } from 'next-redux-wrapper'
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
|
||||
import { inctagramService } from '@/services/inctagram.service'
|
||||
|
||||
const makeStore = () =>
|
||||
configureStore({
|
||||
reducer: {
|
||||
[inctagramService.reducerPath]: inctagramService.reducer,
|
||||
},
|
||||
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(inctagramService.middleware),
|
||||
devTools: true,
|
||||
})
|
||||
|
||||
export type AppStore = ReturnType<typeof makeStore>
|
||||
export type AppState = ReturnType<AppStore['getState']>
|
||||
export type AppDispatch = AppStore['dispatch']
|
||||
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, AppState, unknown, Action>
|
||||
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>()
|
||||
export const useAppSelector: TypedUseSelectorHook<AppState> = useSelector
|
||||
|
||||
export const wrapper = createWrapper<AppStore>(makeStore)
|
||||
Reference in New Issue
Block a user