Update client side. fix previous errors
parent
ac24e8bbd8
commit
056c41000d
|
@ -0,0 +1,4 @@
|
|||
schema:
|
||||
- http://localhost:8000/api/v1/graphql:
|
||||
headers:
|
||||
Authorization: Bearer eyJ1c2VyX2lkIjogMSwgInNhbHQiOiAiMTkxNDZhIiwgImV4cGlyZXMiOiAxNzIxMjMyMzM3Ljk4MTUyN30HZ3bA-tzG2JebZhmLQJRmODYQj6_aM1ZEQ23uDJreKg==
|
|
@ -1,4 +1,6 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
const nextConfig = {
|
||||
reactStrictMode: false
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
|
@ -10,7 +10,11 @@
|
|||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"@ant-design/nextjs-registry": "^1.0.0",
|
||||
"@apollo/client": "^3.10.8",
|
||||
"@apollo/experimental-nextjs-app-support": "^0.11.2",
|
||||
"antd": "^5.19.2",
|
||||
"graphql": "^16.9.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
|
@ -111,6 +115,73 @@
|
|||
"react": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@apollo/client": {
|
||||
"version": "3.10.8",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.10.8.tgz",
|
||||
"integrity": "sha512-UaaFEitRrPRWV836wY2L7bd3HRCfbMie1jlYMcmazFAK23MVhz/Uq7VG1nwbotPb5xzFsw5RF4Wnp2G3dWPM3g==",
|
||||
"dependencies": {
|
||||
"@graphql-typed-document-node/core": "^3.1.1",
|
||||
"@wry/caches": "^1.0.0",
|
||||
"@wry/equality": "^0.5.6",
|
||||
"@wry/trie": "^0.5.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"optimism": "^0.18.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"rehackt": "^0.1.0",
|
||||
"response-iterator": "^0.2.6",
|
||||
"symbol-observable": "^4.0.0",
|
||||
"ts-invariant": "^0.10.3",
|
||||
"tslib": "^2.3.0",
|
||||
"zen-observable-ts": "^1.2.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^15.0.0 || ^16.0.0",
|
||||
"graphql-ws": "^5.5.5",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"subscriptions-transport-ws": "^0.9.0 || ^0.11.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"graphql-ws": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"subscriptions-transport-ws": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@apollo/client-react-streaming": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/client-react-streaming/-/client-react-streaming-0.11.2.tgz",
|
||||
"integrity": "sha512-rRA/dIA09/Y6+jtGGBnXHQfPOv6BYYVZwQP8OzQtWrWbSgDEI6uAhqULssU5f0ZhQJVzKDuslqGE9QAX0gdfRQ==",
|
||||
"dependencies": {
|
||||
"ts-invariant": "^0.10.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@apollo/client": "^3.10.4",
|
||||
"react": "^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@apollo/experimental-nextjs-app-support": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/experimental-nextjs-app-support/-/experimental-nextjs-app-support-0.11.2.tgz",
|
||||
"integrity": "sha512-HRQ8/Ux/tM2pezrhZeoHsJs55+nJvJZRV1B21QwEVtWhslQXjT5gqs5nKw86KURF0xR7gX18Nyy659NzJ09Pmw==",
|
||||
"dependencies": {
|
||||
"@apollo/client-react-streaming": "0.11.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@apollo/client": "^3.10.4",
|
||||
"next": "^13.4.1 || ^14.0.0 || 15.0.0-rc.0",
|
||||
"react": "^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz",
|
||||
|
@ -196,6 +267,14 @@
|
|||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@graphql-typed-document-node/core": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz",
|
||||
"integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==",
|
||||
"peerDependencies": {
|
||||
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
|
@ -816,6 +895,50 @@
|
|||
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@wry/caches": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz",
|
||||
"integrity": "sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@wry/context": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz",
|
||||
"integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@wry/equality": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz",
|
||||
"integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@wry/trie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz",
|
||||
"integrity": "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.12.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
||||
|
@ -2632,6 +2755,28 @@
|
|||
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/graphql": {
|
||||
"version": "16.9.0",
|
||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz",
|
||||
"integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/graphql-tag": {
|
||||
"version": "2.12.6",
|
||||
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
|
||||
"integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-bigints": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
|
||||
|
@ -2713,6 +2858,14 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||
|
@ -3216,6 +3369,14 @@
|
|||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -3560,7 +3721,6 @@
|
|||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -3701,6 +3861,28 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/optimism": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz",
|
||||
"integrity": "sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==",
|
||||
"dependencies": {
|
||||
"@wry/caches": "^1.0.0",
|
||||
"@wry/context": "^0.7.0",
|
||||
"@wry/trie": "^0.4.3",
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/optimism/node_modules/@wry/trie": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz",
|
||||
"integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
|
@ -4024,7 +4206,6 @@
|
|||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
|
@ -4663,8 +4844,7 @@
|
|||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
|
@ -4731,6 +4911,23 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/rehackt": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz",
|
||||
"integrity": "sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
|
@ -4771,6 +4968,14 @@
|
|||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/response-iterator": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz",
|
||||
"integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
|
@ -5308,6 +5513,14 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/symbol-observable": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
|
||||
"integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz",
|
||||
|
@ -5424,6 +5637,17 @@
|
|||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-invariant": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz",
|
||||
"integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
|
@ -5808,6 +6032,19 @@
|
|||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zen-observable": {
|
||||
"version": "0.8.15",
|
||||
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
|
||||
"integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="
|
||||
},
|
||||
"node_modules/zen-observable-ts": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz",
|
||||
"integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==",
|
||||
"dependencies": {
|
||||
"zen-observable": "0.8.15"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"@ant-design/nextjs-registry": "^1.0.0",
|
||||
"@apollo/client": "^3.10.8",
|
||||
"@apollo/experimental-nextjs-app-support": "^0.11.2",
|
||||
"antd": "^5.19.2",
|
||||
"axios": "^1.7.9",
|
||||
"graphql": "^16.9.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import {cookies} from "next/headers";
|
||||
import {redirect} from "next/navigation";
|
||||
|
||||
export default function Loading() {
|
||||
if (cookies().get("session_token")) {
|
||||
return redirect('/my')
|
||||
}
|
||||
}
|
|
@ -1,16 +1,46 @@
|
|||
"use client"
|
||||
|
||||
import {Form, Button, Input} from "antd";
|
||||
import {Form, Button, Input, message} from "antd";
|
||||
import {useRouter} from "next/navigation";
|
||||
|
||||
|
||||
const msgLoginSuccess = () => message.success("Вы успешно вошли в систему")
|
||||
const msgLoginError = () => message.error("Неверный логин или пароль")
|
||||
|
||||
const AuthPage = () => {
|
||||
const router = useRouter()
|
||||
const onFinish = (values) => {
|
||||
|
||||
fetch("http://localhost:8000/api/v1/auth", {
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
body: JSON.stringify(values)
|
||||
}).then((response) => {
|
||||
if (response.ok) {
|
||||
msgLoginSuccess()
|
||||
router.push("/my")
|
||||
} else {
|
||||
msgLoginError()
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form>
|
||||
<Form.Item label={"Логин"}>
|
||||
<Input />
|
||||
<Form
|
||||
onFinish={onFinish}
|
||||
onSubmitCapture={(e) => {
|
||||
e.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Form.Item name={"login"} label={"Логин"}
|
||||
rules={[{required: true, message: "Введите e-mail или логин"}]}>
|
||||
<Input/>
|
||||
</Form.Item>
|
||||
<Form.Item label={"Пароль"}>
|
||||
<Form.Item name={"password"} label={"Пароль"} rules={[{required: true, message: "Введите пароль"}]}>
|
||||
<Input.Password></Input.Password>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
|
|
|
@ -2,29 +2,6 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/*:root {*/
|
||||
/* --foreground-rgb: 0, 0, 0;*/
|
||||
/* --background-start-rgb: 214, 219, 220;*/
|
||||
/* --background-end-rgb: 255, 255, 255;*/
|
||||
/*}*/
|
||||
|
||||
/*@media (prefers-color-scheme: dark) {*/
|
||||
/* :root {*/
|
||||
/* --foreground-rgb: 255, 255, 255;*/
|
||||
/* --background-start-rgb: 0, 0, 0;*/
|
||||
/* --background-end-rgb: 0, 0, 0;*/
|
||||
/* }*/
|
||||
/*}*/
|
||||
|
||||
/*body {*/
|
||||
/* color: rgb(var(--foreground-rgb));*/
|
||||
/* background: linear-gradient(*/
|
||||
/* to bottom,*/
|
||||
/* transparent,*/
|
||||
/* rgb(var(--background-end-rgb))*/
|
||||
/* )*/
|
||||
/* rgb(var(--background-start-rgb));*/
|
||||
/*}*/
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
|
|
|
@ -3,6 +3,7 @@ import "./globals.css";
|
|||
import {Col, ConfigProvider, Layout, Row, Typography} from "antd";
|
||||
import Logo from "@/components/header/logo";
|
||||
import {AntdRegistry} from "@ant-design/nextjs-registry";
|
||||
import Link from "next/link";
|
||||
|
||||
|
||||
const inter = Inter({subsets: ["latin"]});
|
||||
|
@ -17,27 +18,33 @@ export default function RootLayout({children}) {
|
|||
<html lang="en">
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: "#E5332A",
|
||||
},
|
||||
components: {
|
||||
// Button: {
|
||||
// colorPrimary: "#E5332A",
|
||||
// colorText: "#E5332A",
|
||||
// colorPrimaryHover: "#ea6761",
|
||||
// },
|
||||
Typography: {
|
||||
titleMarginBottom: 0
|
||||
|
||||
},
|
||||
}
|
||||
}}>
|
||||
<AntdRegistry>
|
||||
|
||||
<body className={inter.className}>
|
||||
<header className={"mb-14"}>
|
||||
<Row className={"items-center py-5"}>
|
||||
<Col span={6} offset={3}>
|
||||
<Logo/>
|
||||
<Link href={"/"}><Logo/></Link>
|
||||
</Col>
|
||||
<Col>
|
||||
<span className={"font-bold text-2xl"}>Система Обновлений MPUpdate</span>
|
||||
</Col>
|
||||
</Row>
|
||||
</header>
|
||||
{children}
|
||||
{children}
|
||||
</body>
|
||||
</AntdRegistry>
|
||||
</ConfigProvider>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
"use client"
|
||||
import {Col, Row} from "antd";
|
||||
import UpdationTable from "@/components/my/application/updationTable";
|
||||
import Title from "@/components/my/application/title"
|
||||
import AddUpdate from "@/components/my/application/addUpdateModal";
|
||||
import {useEffect, useState} from "react";
|
||||
import AppService from "@/services/appService";
|
||||
|
||||
|
||||
|
||||
const ApplicationPage = ({params: { appId }}) => {
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [appData, setAppData] = useState({
|
||||
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true)
|
||||
AppService.listApplications().then((res) => {
|
||||
console.log(res.data[appId])
|
||||
setAppData(res.data[appId])
|
||||
setIsLoading(false)
|
||||
})
|
||||
}, [appId]);
|
||||
return (
|
||||
<>
|
||||
<Row className={"items-center mb-4"}>
|
||||
<Col span={12}>
|
||||
<Title>{appData.appName}</Title>
|
||||
</Col>
|
||||
<AddUpdate appId={appData.id}/>
|
||||
</Row>
|
||||
|
||||
<UpdationTable dataSource={appData.versions} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ApplicationPage
|
|
@ -0,0 +1,14 @@
|
|||
import {Col, Row} from "antd";
|
||||
|
||||
export const metadata = {
|
||||
title: "Список приложений | Система обновлений MPUpdate",
|
||||
};
|
||||
|
||||
export default function AppWrapper({children}) {
|
||||
return (
|
||||
<Row className={"justify-center items-center"}>
|
||||
<Col span={16}>{children}</Col>
|
||||
</Row>
|
||||
|
||||
)
|
||||
}
|
|
@ -1,13 +1,27 @@
|
|||
"use client"
|
||||
import {Button, Col, Form, Input, Modal, Row, Table, Typography} from "antd";
|
||||
import {useState} from "react";
|
||||
import {Button, Col, Row, Table, Typography} from "antd";
|
||||
import {useEffect, useState} from "react";
|
||||
import CreateAppModal from "@/components/my/createAppModal";
|
||||
import {useRouter} from "next/navigation";
|
||||
import AppService from "@/services/appService";
|
||||
|
||||
|
||||
const MyPage = () => {
|
||||
|
||||
const [apps, setApps] = useState([])
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const router = useRouter()
|
||||
const [isCreateAppModalOpened, setIsCreateAppModalOpened] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true)
|
||||
AppService.listApplications().then((res) => {
|
||||
setApps(Object.values(res.data))
|
||||
setIsLoading(false)
|
||||
})
|
||||
|
||||
}, []);
|
||||
|
||||
const handleOkIsCreateAppModalOpened = () => {
|
||||
setIsCreateAppModalOpened(false)
|
||||
}
|
||||
|
@ -18,37 +32,33 @@ const MyPage = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Row className={"justify-center items-center"}>
|
||||
<Col span={16}>
|
||||
<Row className={"mb-4 items-center justify-between"}>
|
||||
<Col>
|
||||
<Typography.Title className={"pb-0 mb-0"}>Список приложений</Typography.Title>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button type={"primary"} onClick={() => setIsCreateAppModalOpened(true)}>Добавить приложение</Button>
|
||||
</Col>
|
||||
|
||||
|
||||
</Row>
|
||||
|
||||
<Table>
|
||||
<Table.Column title={"Приложение"} dataIndex={"appName"}/>
|
||||
<Table.Column title={"Описание"} dataIndex={"name"} key={"name"}/>
|
||||
<Table.Column title={"Последняя версия"} dataIndex={"email"} key={"email"}/>
|
||||
<Table.Column render={(d) => {
|
||||
return <Button onClick={() => {
|
||||
console.log(d);
|
||||
}}>Изменить</Button>
|
||||
}
|
||||
}></Table.Column>
|
||||
</Table>
|
||||
<Row className={"mb-4"}>
|
||||
<Col span={12}>
|
||||
<Typography.Title className={"pb-0 mb-0"}>Список приложений</Typography.Title>
|
||||
</Col>
|
||||
<Col offset={6} span={6}>
|
||||
<Button type={"primary"} className={"w-full"} onClick={() => setIsCreateAppModalOpened(true)}>Добавить
|
||||
приложение</Button>
|
||||
</Col>
|
||||
|
||||
|
||||
</Row>
|
||||
|
||||
<Table dataSource={apps} loading={isLoading}>
|
||||
<Table.Column title={"Приложение"} dataIndex={"appName"}/>
|
||||
<Table.Column title={"Описание"} dataIndex={"description"}/>
|
||||
<Table.Column title={"Последняя версия"} render={(d) => <span>{d.versions[0].id}</span>}/>
|
||||
<Table.Column render={(d) => {
|
||||
return <Button onClick={() => {
|
||||
router.push(`/my/application/${d.id}`)
|
||||
}}>Изменить</Button>
|
||||
}
|
||||
}></Table.Column>
|
||||
</Table>
|
||||
<CreateAppModal isOpen={isCreateAppModalOpened} handleCancel={handleCancelCreateAppModal}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default MyPage;
|
|
@ -1,9 +1,5 @@
|
|||
import Image from "next/image";
|
||||
import {redirect} from "next/navigation";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
|
||||
</main>
|
||||
);
|
||||
return redirect("/my")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
"use client"
|
||||
|
||||
import {Button, Col, Form, Input, Modal, Progress, Row, Typography, Upload} from "antd";
|
||||
import {useState} from "react";
|
||||
import AppService from "@/services/appService";
|
||||
|
||||
export function AddUpdateModalBtn(setIsModalVisible) {
|
||||
return (
|
||||
<Button onClick={() => setIsModalVisible(true)}>Добавить обновление</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export function AddUpdateModal({isVisible, onOk, onCancel}) {
|
||||
const [description, setDescription] = useState("")
|
||||
const [versionId, setVersionId] = useState("")
|
||||
const [link, setLink] = useState("")
|
||||
const [progressUpload, setProgressUpload] = useState(0)
|
||||
|
||||
const sendFileHandler = (file) => {
|
||||
AppService.uploadApp(file, {onProgress: (p) => setProgressUpload(p)}).then(d => {
|
||||
setLink(d.link)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={isVisible} onOk={() => {}} onCancel={onCancel} okText={"Добавить обновление"} footer={() => <></>}>
|
||||
<Row className={"mt-10 w-full"}>
|
||||
<Col span={24}>
|
||||
<Form>
|
||||
<Row className={"items-center"}>
|
||||
<Col span={11} className={"mr-4"}>
|
||||
<Form.Item label={"Описание"} layout={"horizontal"} name={"description"} required={true}>
|
||||
<Input.TextArea placeholder={"Введите описание для обновления"} value={description} onChange={e => setDescription(e.target.value)}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
<Col span={11}>
|
||||
<Form.Item label={"Версия"} required={true} name={"version"}>
|
||||
<Input placeholder={"0.0.1"} value={versionId} onChange={e => setVersionId(e.target.value)}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Col span={24}>
|
||||
<Form.Item name={"link"}>
|
||||
<Progress percent={progressUpload}/>
|
||||
<input type="file" onChange={e => sendFileHandler(e.target.files[0])}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
|
||||
</Form>
|
||||
</Col>
|
||||
</Row>
|
||||
<Button type={"primary"} onClick={() => onOk({id: versionId, description, link})}>Добавить обновление</Button>
|
||||
|
||||
</Modal>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default function AddUpdate({appId}) {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const onOkCb = ({id, link, description}) => {
|
||||
if (id )
|
||||
AppService.addVersion({id, appId, link, description}).then(d => {
|
||||
setIsModalVisible(false)
|
||||
})
|
||||
|
||||
}
|
||||
const onCancelCb = () => {
|
||||
setIsModalVisible(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Col span={6} offset={6}>
|
||||
<Button onClick={() => setIsModalVisible(true)} type={"primary"} className={"w-full"}>Добавить
|
||||
обновление</Button>
|
||||
</Col>
|
||||
<AddUpdateModal isVisible={isModalVisible} onOk={onOkCb} onCancel={onCancelCb}/>
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
"use client"
|
||||
import {Typography} from "antd";
|
||||
|
||||
export default function Title({children}) {
|
||||
return <Typography.Title>{children}</Typography.Title>
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
"use client"
|
||||
|
||||
import {Button, Table} from "antd";
|
||||
|
||||
export default function UpdationTable({dataSource}) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table dataSource={dataSource}>
|
||||
<Table.Column title={"Версия"} dataIndex={"id"}/>
|
||||
<Table.Column title={"Описание"} dataIndex={"description"}/>
|
||||
<Table.Column title={"Код Версии"} dataIndex={"versionCode"}/>
|
||||
<Table.Column title={"Ссылка"} dataIndex={"link"} render={(e) => <a href={e}><Button type={"link"}>Скачать</Button></a> }/>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,48 +1,42 @@
|
|||
import {Button, Col, Divider, Form, Input, message, Modal, Row, Space, Typography} from "antd";
|
||||
import Upload from "@/components/my/upload";
|
||||
import {Button, Col, Divider, Form, Input, message, Modal, Progress, Row, Space, Typography} from "antd";
|
||||
|
||||
import {useState} from "react";
|
||||
|
||||
|
||||
const uploadProps = {
|
||||
name: 'file',
|
||||
multiple: false,
|
||||
action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
|
||||
|
||||
beforeUpload: (file) => {
|
||||
const isAPK = file.type === 'application/vnd.android.package-archive';
|
||||
if (!isAPK) {
|
||||
message.error(`${file.name} не является APK файлом`);
|
||||
}
|
||||
return isAPK || Upload.LIST_IGNORE;
|
||||
},
|
||||
|
||||
onChange(info) {
|
||||
const { status } = info.file;
|
||||
if (status !== 'uploading') {
|
||||
console.log(info.file, info.fileList);
|
||||
}
|
||||
if (status === 'done') {
|
||||
message.success(`${info.file.name} file uploaded successfully.`);
|
||||
} else if (status === 'error') {
|
||||
message.error(`${info.file.name} file upload failed.`);
|
||||
}
|
||||
},
|
||||
onDrop(e) {
|
||||
console.log('Dropped files', e.dataTransfer.files);
|
||||
},
|
||||
};
|
||||
import {useRouter} from "next/navigation";
|
||||
import AppService from "@/services/appService";
|
||||
|
||||
|
||||
const CreateAppModal = ({isOpen, handleCancel}) => {
|
||||
|
||||
const router = useRouter()
|
||||
const [isTitleFocused, setIsTitleFocused] = useState(false)
|
||||
const [appName, setAppName] = useState("Название приложения")
|
||||
const [appVersion, setAppVersion] = useState("")
|
||||
const [appDescription, setAppDescription] = useState("")
|
||||
const [link, setLink] = useState()
|
||||
const [appId, setAppId] = useState()
|
||||
|
||||
const [progressUpload, setProgressUpload] = useState(0)
|
||||
|
||||
|
||||
const sendFileHandler = (file) => {
|
||||
AppService.uploadApp(file, {onProgress: (p) => setProgressUpload(p)}).then(d => {
|
||||
setLink(d.link)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={isOpen}
|
||||
onOk={handleCancel}
|
||||
onOk={() => AppService.createApp({
|
||||
id: appId,
|
||||
appName,
|
||||
version: appVersion,
|
||||
description: appDescription,
|
||||
link
|
||||
}).then(() => {
|
||||
handleCancel()
|
||||
router.refresh()
|
||||
})}
|
||||
onCancel={handleCancel}
|
||||
width={"50%"}
|
||||
>
|
||||
|
@ -51,21 +45,28 @@ const CreateAppModal = ({isOpen, handleCancel}) => {
|
|||
<Divider className={"!mt-0"}/>
|
||||
|
||||
<Form>
|
||||
<Form.Item required>
|
||||
<Form.Item required name={"name"}>
|
||||
<Typography.Title level={5} className={isTitleFocused ? "hidden": "inline"} onClick={() => setIsTitleFocused(true)}>{appName}</Typography.Title>
|
||||
<Input value={appName} onChange={e => setAppName(e.target.value)} className={isTitleFocused ? "inline": "!hidden"} />
|
||||
<Button type={"primary"} onClick={() => setIsTitleFocused(false)} className={isTitleFocused ? "inline mt-4": "!hidden"} >Сохранить</Button>
|
||||
</Form.Item>
|
||||
<Row className={"items-center"}>
|
||||
|
||||
<Col span={11} className={"mr-4"}>
|
||||
<Form.Item label={"Описание"} layout={"horizontal"}>
|
||||
<Input.TextArea placeholder={"Введите описание для приложения"}/>
|
||||
<Form.Item label={"Идентификатор"} layout={"horizontal"} name={"id"} required={true}>
|
||||
<Input.TextArea placeholder={"com.example.mp_update"} value={appId} onChange={e => setAppId(e.target.value)}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
<Col span={11} className={"mr-4"}>
|
||||
<Form.Item label={"Описание"} layout={"horizontal"} name={"description"} required={true}>
|
||||
<Input.TextArea placeholder={"Введите описание для приложения"} value={appDescription} onChange={e => setAppDescription(e.target.value)}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
<Col span={11}>
|
||||
<Form.Item label={"Версия"} required={true}>
|
||||
<Input placeholder={"0.0.1"}/>
|
||||
<Form.Item label={"Версия"} required={true} name={"version"}>
|
||||
<Input placeholder={"0.0.1"} value={appVersion} onChange={e => setAppVersion(e.target.value)}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
|
@ -73,11 +74,12 @@ const CreateAppModal = ({isOpen, handleCancel}) => {
|
|||
|
||||
<Row>
|
||||
<Col span={24}>
|
||||
<Upload {...uploadProps}/>
|
||||
<Form.Item name={"link"}>
|
||||
<Progress percent={progressUpload}/>
|
||||
<input type="file" onChange={e => sendFileHandler(e.target.files[0])}/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
|
|
|
@ -1,18 +1,30 @@
|
|||
import {Upload} from 'antd';
|
||||
import {InboxOutlined} from "@ant-design/icons";
|
||||
import AppService from "@/services/appService";
|
||||
|
||||
const UploadComponent = (props) => {
|
||||
return (
|
||||
<Upload.Dragger {...props}>
|
||||
<p className="ant-upload-drag-icon">
|
||||
<InboxOutlined />
|
||||
</p>
|
||||
<p className="ant-upload-text">Загрузка .apk файла</p>
|
||||
<p className="ant-upload-hint">
|
||||
Выберите или перетащите файл в данную область
|
||||
</p>
|
||||
</Upload.Dragger>
|
||||
)
|
||||
|
||||
const uploadHandler = () => {
|
||||
AppService.uploadApp()
|
||||
}
|
||||
|
||||
// const UploadComponent = (props) => {
|
||||
// return (
|
||||
// <Upload.Dragger {...props} action={(file) => {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// AppService.uploadApp(file).then(d =>
|
||||
// resolve(d.data.link)
|
||||
// )
|
||||
// })
|
||||
// }}>
|
||||
// <p className="ant-upload-drag-icon">
|
||||
// <InboxOutlined />
|
||||
// </p>
|
||||
// <p className="ant-upload-text">Загрузка .apk файла</p>
|
||||
// <p className="ant-upload-hint">
|
||||
// Выберите или перетащите файл в данную область
|
||||
// </p>
|
||||
// </Upload.Dragger>
|
||||
// )
|
||||
// }
|
||||
|
||||
export default UploadComponent;
|
|
@ -0,0 +1,50 @@
|
|||
import $instance, {BASE_URL} from "@/services/default";
|
||||
export default class AppService {
|
||||
static async listApplications() {
|
||||
return await $instance.get("/updates/list-app")
|
||||
}
|
||||
|
||||
static uploadApp(file, {onProgress}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest()
|
||||
|
||||
xhr.upload.onprogress = (event) => {
|
||||
onProgress?.(Math.round((event.loaded / event.total) * 100));
|
||||
};
|
||||
|
||||
xhr.open("POST", `${BASE_URL}/updates/upload`)
|
||||
xhr.onload = () => {
|
||||
xhr.status === 200 ? resolve(JSON.parse(xhr.response)) : reject(xhr.response)
|
||||
}
|
||||
|
||||
const fileData = new FormData();
|
||||
fileData.append("version", file)
|
||||
|
||||
xhr.send(fileData)
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
// return await $instance.postForm("/updates/upload", {
|
||||
// "version": file
|
||||
// }, {
|
||||
// headers: {
|
||||
// "Content-Type": "multipart/form-data"
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
static async createApp({id, appName, version, description, link}) {
|
||||
return await $instance.post("/updates/create-app", {
|
||||
id, appName, version, description, link
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
static async addVersion({id, appId, link, description}) {
|
||||
return await $instance.post("/updates/create", {
|
||||
id, appId, link, description
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import axios from "axios";
|
||||
|
||||
export const BASE_URL = "http://localhost:8001/api"
|
||||
|
||||
const $instance = axios.create({
|
||||
baseURL: BASE_URL
|
||||
})
|
||||
|
||||
|
||||
export default $instance;
|
Loading…
Reference in New Issue