diff --git a/frontend/src/app.jsx b/frontend/src/app.jsx
index 0552b25..5e70a9c 100644
--- a/frontend/src/app.jsx
+++ b/frontend/src/app.jsx
@@ -12,7 +12,9 @@ import ComingSoonPage from './pages/coming_soon';
import ModsPage from './pages/mods';
import ModPage from './pages/mod_page'
+import ModVersionsPage from './pages/mod_versions'
import ModCreationPage from './pages/mod_creation'
+import ModVersionCreationPage from './pages/create_mod_version'
import ModpacksPage from './pages/modpacks';
@@ -50,6 +52,8 @@ export function App() {
+
+
diff --git a/frontend/src/assets/game.svg b/frontend/src/assets/game.svg
new file mode 100644
index 0000000..8f04fc0
--- /dev/null
+++ b/frontend/src/assets/game.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/hardware_platform.svg b/frontend/src/assets/hardware_platform.svg
new file mode 100644
index 0000000..847d932
--- /dev/null
+++ b/frontend/src/assets/hardware_platform.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/loader.svg b/frontend/src/assets/loader.svg
new file mode 100644
index 0000000..1ef60b2
--- /dev/null
+++ b/frontend/src/assets/loader.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/pages/create_mod_version.jsx b/frontend/src/pages/create_mod_version.jsx
new file mode 100644
index 0000000..c6eae6f
--- /dev/null
+++ b/frontend/src/pages/create_mod_version.jsx
@@ -0,0 +1,269 @@
+// Preact
+import { h } from 'preact';
+import { useState, useEffect } from 'preact/hooks';
+import Cookies from 'js-cookie'
+import { jwtDecode } from 'jwt-decode'
+
+// Functions
+import { createModVersion } from '../services/mods';
+
+// Components
+import InputField from '../components/Fields/input_field'
+import TextArea from '../components/Fields/text_area'
+
+// Images
+import logo from '../assets/logo.png'
+import profile from '../assets/profile.svg'
+
+// Styles
+import styles from '../styles/version_creation.module.css'
+import Button from '../components/Buttons/button';
+
+function ModVersionCreationPage({name}) {
+ //TODO add missing fields
+
+ const null_fields = {
+ version_number: null,
+ channel: null,
+ changelog: null,
+ game_version: null,
+ platform: null,
+ environment: null,
+ url: null
+ }
+
+ //TODO use a service
+ let user;
+ const token = Cookies.get('authToken');
+ if (token) {
+ const decoded_token = jwtDecode(token);
+ if (decoded_token) {
+ user = decoded_token.username;
+ } else {
+ location.replace('/login')
+ }
+ } else {
+ location.replace('/login')
+ }
+
+ const [version_number, setVersionNumber] = useState('');
+ const [channel, setChannel] = useState('');
+ const [game_version, setGameVersion] = useState('');
+ const [platform, setPlatform] = useState('');
+ const [environment, setEnvironment] = useState('');
+ const [changelog, setChangelog] = useState('');
+ const [version_url, setVersionUrl] = useState('');
+
+ const [publish_status, setPublishStatus] = useState(null);
+ const [field_errors, setFieldErrors] = useState(null_fields);
+
+
+ // Handle fields changes
+
+ const handleVersionNumberChange = (event) => {
+ setVersionNumber(event.target.value);
+ // Reset error
+ setFieldErrors(prevErrors => ({ ...prevErrors, version_number: null }));
+ };
+ const handleChannelChange = (event) => {
+ setChannel(event.target.value);
+ setFieldErrors(prevErrors => ({ ...prevErrors, channel: null }));
+ };
+ const handleGameVersionChange = (event) => {
+ setGameVersion(event.target.value);
+ setFieldErrors(prevErrors => ({ ...prevErrors, game_version: null }));
+ };
+ const handlePlatformChange = (event) => {
+ setPlatform(event.target.value);
+ console.debug(event.target.value);
+ setFieldErrors(prevErrors => ({ ...prevErrors, platform: null }));
+ };
+ const handleEnvironmentChange = (event) => {
+ setEnvironment(event.target.value);
+ console.debug(event.target.value);
+ setFieldErrors(prevErrors => ({ ...prevErrors, environment: null }));
+ };
+ const handleChangelogChange = (event) => {
+ setChangelog(event.target.value);
+ console.debug(event.target.value);
+ setFieldErrors(prevErrors => ({ ...prevErrors, changelog: null }));
+ };
+ const handleVersionUrlChange = (event) => {
+ setVersionUrl(event.target.value);
+ console.debug(event.target.value);
+ setFieldErrors(prevErrors => ({ ...prevErrors, version_url: null }));
+ };
+
+ // Submission
+
+ const handleSubmit = async (event) => {
+ event.preventDefault();
+ setFieldErrors(null_fields);
+
+ setPublishStatus('publishing');
+
+ try {
+ // Gather data
+ const version_data = {
+ version_number: version_number,
+ channel: channel,
+ changelog: changelog,
+ game_version: changelog,
+ platform: changelog,
+ environment: changelog,
+ url: version_url
+ }
+
+ // Query
+ const response = await createModVersion(name, version_data);
+
+ // On success
+ console.debug('Published successfully:', response);
+ setPublishStatus('success');
+ window.location.replace("/mods/" + name + "/versions"); //TODO no page reloading
+
+ } catch (error) {
+
+ console.error('Creation failed:', error);
+ setPublishStatus('error');
+
+ //TODO handle different codes differently
+ setFieldErrors({
+ version_number: ' ',
+ channel: ' ',
+ changelog: ' ',
+ game_version: ' ',
+ platform: ' ',
+ environment: ' ',
+ version_url: ' '
+ });
+ }
+ finally {
+ setPublishStatus(null);
+ }
+ };
+
+ return (
+ <>
+
+
+ creator
+
+
+
+
+
+
+
+
+

+
{user}
+
+
+
+
+ >)
+}
+
+export default ModVersionCreationPage
\ No newline at end of file
diff --git a/frontend/src/pages/mod_page.jsx b/frontend/src/pages/mod_page.jsx
index 47cc66a..dcdd2c4 100644
--- a/frontend/src/pages/mod_page.jsx
+++ b/frontend/src/pages/mod_page.jsx
@@ -5,7 +5,7 @@ import Cookies from 'js-cookie'
import { jwtDecode } from 'jwt-decode'
// Functions
-import { getMod, deleteMod } from '../services/mods';
+import { getMod, deleteMod, getModVersions } from '../services/mods';
// Components
import Button from '../components/Buttons/button';
@@ -26,6 +26,7 @@ function ModPage({name}) {
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [owner, setOwner] = useState(false);
+ const [versions, setVersions] = useState(null);
// UseEffect
useEffect(() => {
@@ -34,8 +35,11 @@ function ModPage({name}) {
setLoading(true);
setError(false);
try {
- const fetched_mod = await getMod(name);
- setMod(fetched_mod);
+ const fetched_mod = getMod(name);
+ const fetched_versions = getModVersions(name, {});
+ setMod( await fetched_mod);
+ setVersions( await fetched_versions);
+
} catch (err) {
setError(err.message);
} finally {
@@ -53,18 +57,19 @@ function ModPage({name}) {
location.replace('/dashboard');
};
- // Load user informations
- //TODO use a service
- //? for some reason, doesn't work inside useEffect
- const token = Cookies.get('authToken');
- if (token) {
- const decoded_token = jwtDecode(token);
- if (decoded_token) {
- if (decoded_token.username === mod.author) {
- setOwner(true);
- }
+
+ // Load user informations
+ //TODO use a service
+ //? for some reason, doesn't work inside useEffect
+ const token = Cookies.get('authToken');
+ if (token) {
+ const decoded_token = jwtDecode(token);
+ if (decoded_token) {
+ if (decoded_token.username === mod.author) {
+ setOwner(true);
}
}
+ }
const base_page = (
<>
@@ -139,35 +144,35 @@ function ModPage({name}) {
Versions
{ owner ? (
+