Merge branch 'main' of https://git.missing.ninja/LF2/Alisa
This commit is contained in:
commit
50d5ead7bf
6 changed files with 167 additions and 87 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>("");
|
||||||
|
|
||||||
|
|
|
@ -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
14
web/src/types.ts
Normal 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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue