This commit is contained in:
BurnLP2013 2024-07-11 12:50:05 +02:00
commit 50d5ead7bf
6 changed files with 167 additions and 87 deletions

View file

@ -4,7 +4,7 @@ import QtQuick.Controls.Basic
Window { Rectangle {
SystemPalette { id: activeColors; colorGroup: SystemPalette.Active } SystemPalette { id: activeColors; colorGroup: SystemPalette.Active }
SystemPalette { id: inactiveColors; colorGroup: SystemPalette.Inactive } SystemPalette { id: inactiveColors; colorGroup: SystemPalette.Inactive }
@ -14,9 +14,6 @@ Window {
return root.active ? activeColors : inactiveColors; return root.active ? activeColors : inactiveColors;
} }
width: 400
height: 400
visible: true visible: true
signal loginSuccess(string token) signal loginSuccess(string token)
@ -42,25 +39,29 @@ Window {
id: nameT id: nameT
anchors{ anchors{
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
topMargin: 5 topMargin: 5
top: loginL.bottom top: loginL.bottom
} }
placeholderText: qsTr("Name") placeholderText: qsTr("Name")
Keys.onReturnPressed: passwordField.focus = true
} }
TextField { TextField {
id: passwordT id: passwordT
anchors{ anchors{
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
topMargin: 5 topMargin: 5
top: nameT.bottom top: nameT.bottom
} }
placeholderText: qsTr("Password") placeholderText: qsTr("Password")
Keys.onReturnPressed: login()
echoMode: TextInput.Password echoMode: TextInput.Password
} }
@ -74,25 +75,27 @@ Window {
text: qsTr("Submit") text: qsTr("Submit")
onClicked: { onClicked: login()
var xhr = new XMLHttpRequest(); }
xhr.open("POST", "https://api.clan-war.net/api/v1/auth/login");
xhr.setRequestHeader("Content-Type", "application/json"); function login() {
xhr.onreadystatechange = function() { var xhr = new XMLHttpRequest();
if (xhr.readyState === XMLHttpRequest.DONE) { xhr.open("POST", "https://api.clan-war.net/api/v1/auth/login");
if (xhr.status === 200) { xhr.setRequestHeader("Content-Type", "application/json");
var token = xhr.responseText.trim(); // Trim to remove any leading/trailing whitespace xhr.onreadystatechange = function() {
loginSuccess(token); if (xhr.readyState === XMLHttpRequest.DONE) {
} else { if (xhr.status === 200) {
console.log("Login failed: " + xhr.status); var token = xhr.responseText.trim(); // Trim to remove any leading/trailing whitespace
} loginSuccess(token);
} else {
console.log("Login failed: " + xhr.status);
} }
} }
var data = JSON.stringify({
email: nameT.text,
password: passwordT.text
});
xhr.send(data);
} }
var data = JSON.stringify({
email: nameT.text,
password: passwordT.text
});
xhr.send(data);
} }
} }

View file

@ -18,7 +18,7 @@ Window {
visible: true visible: true
color: getColors().window color: getColors().window
title: qsTr("Alisa - License Managment") title: qsTr("Alisa - License Management")
property string authToken: "" property string authToken: ""
@ -31,9 +31,9 @@ Window {
Component { Component {
id: loginPageComponent id: loginPageComponent
LoginScreen { LoginScreen {
onLoginSuccess: { onLoginSuccess: function(token) {
authToken = token authToken = token;
stackView.push(mainPageComponent) stackView.push(mainPageComponent);
} }
} }
} }
@ -42,6 +42,9 @@ Window {
id: mainPageComponent id: mainPageComponent
MainPage { MainPage {
authToken: authToken authToken: authToken
onLogout: {
stackView.push(loginPageComponent)
}
} }
} }
} }

View file

@ -14,6 +14,8 @@ Rectangle {
property string authToken: "" property string authToken: ""
signal logout()
Rectangle { Rectangle {
id: s1 id: s1
anchors { anchors {
@ -21,7 +23,6 @@ Rectangle {
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
radius: 0
height: 50 height: 50
color: getColors().midlight color: getColors().midlight
@ -29,26 +30,24 @@ Rectangle {
anchors{ anchors{
verticalCenter: s1.verticalCenter verticalCenter: s1.verticalCenter
rightMargin: 5 rightMargin: 5
right: logginB.left right: loginB.left
} }
placeholderText: qsTr("Seach") placeholderText: qsTr("Search")
} }
Button{ Button{
id: logginB id: loginB
anchors{ anchors{
verticalCenter: s1.verticalCenter verticalCenter: s1.verticalCenter
rightMargin: 10 rightMargin: 10
right: s1.right right: s1.right
} }
text: qsTr("Login") text: qsTr("Logout")
onClicked: { onClicked: {
var component = Qt.createComponent("LoginScreen.qml") logout();
var window = component.createObject(root)
window.show()
} }
} }
} }
@ -97,34 +96,17 @@ Rectangle {
} }
} }
Button {
id: testB
anchors {
bottom: parent.bottom
left: parent.left
}
text: qsTr("Test Window")
onClicked: {
var component = Qt.createComponent("Test.qml")
var window = component.createObject(root)
window.show()
}
}
Button { Button {
id: loginScreenB id: loginScreenB
anchors { anchors {
left: testB.right
bottom: parent.bottom bottom: parent.bottom
left: parent.left
} }
text: qsTr("Login Screen") text: qsTr("Login Screen")
onClicked: { onClicked: {
var component = Qt.createComponent("LoginScreen.qml") logout();
var window = component.createObject(root)
window.show()
} }
} }
} }

View file

@ -76,8 +76,31 @@
:rules="licenseNameRules" :rules="licenseNameRules"
class="mb-3" class="mb-3"
></v-text-field> ></v-text-field>
<v-text-field
label="License Key *"
v-model="addLicenseKey"
variant="outlined"
required
clearable
:rules="licenseKeyRules"
class="mb-3"
></v-text-field>
<v-autocomplete
clearable
label="Select Group *"
:items="data"
variant="outlined"
:rules="selectGroupRules"
class="mb-1"
v-model="addLicenseGroup"
></v-autocomplete>
<!-- Divider maybe remove -->
<v-divider
class="border-opacity-50"
:thickness="2"
></v-divider>
<div> <div>
<div class="mb-3"> <div class="mb-3 mt-3">
<v-date-input <v-date-input
label="Start Date (optional)" label="Start Date (optional)"
variant="outlined" variant="outlined"
@ -85,9 +108,10 @@
prepend-inner-icon="mdi-calendar-check" prepend-inner-icon="mdi-calendar-check"
clearable clearable
v-model="addStartDate" v-model="addStartDate"
hide-details
></v-date-input> ></v-date-input>
</div> </div>
<div class="mb-5"> <div class="mb-6">
<v-date-input <v-date-input
label="Stop Date (optional)" label="Stop Date (optional)"
variant="outlined" variant="outlined"
@ -95,6 +119,7 @@
prepend-inner-icon="mdi-calendar-remove" prepend-inner-icon="mdi-calendar-remove"
clearable clearable
v-model="addStopDate" v-model="addStopDate"
hide-details
></v-date-input> ></v-date-input>
</div> </div>
</div> </div>
@ -161,7 +186,33 @@
import { store } from "@/store"; import { store } from "@/store";
import { SubmitEventPromise } from "vuetify"; import { SubmitEventPromise } from "vuetify";
import { ref } from "vue"; import { ref } from "vue";
import { Plus, LogOut, FolderPlus } from "lucide-vue-next"; import { Plus, LogOut, Pencil, FolderPlus } from "lucide-vue-next";
import { useQuery } from "@tanstack/vue-query";
import axios from "axios";
import { LicenseGroup } from "@/types";
const { data } = useQuery({
queryKey: ["licenses"],
queryFn: async () => {
const res = await axios.get<LicenseGroup[]>(
import.meta.env.VITE_BACKEND_URL + "/licenses",
{
headers: {
Authorization: `Bearer ${store.token}`,
},
}
);
return res.data;
},
select: (data) => {
return data.map((group) => {
return {
title: group.name,
value: group.id,
};
});
},
});
function handlelogout() { function handlelogout() {
store.setToken(null); store.setToken(null);
@ -169,8 +220,21 @@ function handlelogout() {
async function submit(event: SubmitEventPromise) { async function submit(event: SubmitEventPromise) {
const result = await event; const result = await event;
console.log(result); if (result.valid) {
console.log({
name: addLicenseName.value,
group_id: addLicenseGroup.value,
amount: addAmount.value,
key: addLicenseKey.value,
start: addStartDate.value,
stop: addStopDate.value,
notes: addNotes.value,
});
} else {
console.log("Invalid");
}
} }
// //
// GROUP SECTION // GROUP SECTION
// //
@ -178,6 +242,7 @@ async function submit(event: SubmitEventPromise) {
const group = ref(false); // Dialog for Group const group = ref(false); // Dialog for Group
const groupLicenseName = ref<string>(""); const groupLicenseName = ref<string>("");
// Rules for Group Dialog
const licenseGroupRules = [ const licenseGroupRules = [
(value: string) => { (value: string) => {
if (value) return true; if (value) return true;
@ -191,6 +256,10 @@ const licenseGroupRules = [
const add = ref(false); const add = ref(false);
// References for Add License Dialog // References for Add License Dialog
const addLicenseName = ref<string>(""); const addLicenseName = ref<string>("");
const addLicenseKey = ref<string>("");
const addLicenseGroup = ref<string>();
// Rules for Add License Dialog
const licenseNameRules = [ const licenseNameRules = [
(value: string) => { (value: string) => {
if (value) return true; if (value) return true;
@ -198,6 +267,22 @@ const licenseNameRules = [
return "YOU MUST ENTER (A LICENSE NAME)"; return "YOU MUST ENTER (A LICENSE NAME)";
}, },
]; ];
const selectGroupRules = [
(value: string) => {
if (value) return true;
return "YOU MUST SELECT (A LICENSE GROUP)";
},
];
const licenseKeyRules = [
(value: string) => {
if (value) return true;
return "YOU MUST ENTER (A LICENSE KEY)";
},
];
// Optional Fields
const addAmount = ref<number | undefined>(); const addAmount = ref<number | undefined>();
const addNotes = ref<string | undefined>(""); const addNotes = ref<string | undefined>("");

View file

@ -6,7 +6,10 @@
<div v-else-if="isError">Error: {{ error?.message }}</div> <div v-else-if="isError">Error: {{ error?.message }}</div>
<ul v-else-if="data"> <ul v-else-if="data">
<li v-for="group in data" :key="group.id"> <li v-for="group in data" :key="group.id">
<CategoryContainer :licenseGroupName="group.name" :licenses="group.licenses" /> <CategoryContainer
:licenseGroupName="group.name"
:licenses="group.licenses"
/>
</li> </li>
</ul> </ul>
</div> </div>
@ -19,37 +22,27 @@ import CategoryContainer from "./CategoryContainer.vue";
import { useQuery } from "@tanstack/vue-query"; import { useQuery } from "@tanstack/vue-query";
import axios from "axios"; import axios from "axios";
import { store } from "@/store"; import { store } from "@/store";
import { LicenseGroup } from "@/types";
interface LicenseGroup { const { isPending, isError, data, error } = useQuery({
id: string,
name: string,
licenses: License[]
}
interface License {
name: string;
id: string;
start?: Date,
end?: Date,
key: string,
amount?: number,
}
const {isPending, isError, data, error} = useQuery({
queryKey: ["licenses"], queryKey: ["licenses"],
queryFn: async () => { queryFn: async () => {
const res = await axios.get<LicenseGroup[]>(import.meta.env.VITE_BACKEND_URL + "/licenses", { const res = await axios.get<LicenseGroup[]>(
headers: { import.meta.env.VITE_BACKEND_URL + "/licenses",
Authorization: `Bearer ${store.token}` {
headers: {
Authorization: `Bearer ${store.token}`,
},
} }
}) );
return res.data return res.data;
} },
}) });
</script> </script>
<style scoped> <style scoped>
li, ul { li,
ul {
list-style-type: none; list-style-type: none;
} }
</style> </style>

14
web/src/types.ts Normal file
View file

@ -0,0 +1,14 @@
export interface LicenseGroup {
id: string;
name: string;
licenses: License[];
}
export interface License {
name: string;
id: string;
start?: Date;
end?: Date;
key: string;
amount?: number;
}