feat: Implement changing team settings
parent
f0e2e28d65
commit
40641f80a3
|
@ -38,6 +38,7 @@
|
|||
--crust: #dce0e8;
|
||||
|
||||
--red: #d20f39;
|
||||
--blue: #1e66f5;
|
||||
|
||||
--flamingo: #dd7878;
|
||||
--flamingo-transparent: #f0c6c655;
|
||||
|
@ -52,13 +53,11 @@
|
|||
*/
|
||||
--green-transparent: color-mix(in srgb, var(--green), transparent 80%);
|
||||
--yellow-transparent: color-mix(in srgb, var(--yellow), transparent 80%);
|
||||
/*
|
||||
--green-transparent-50: #a6e3a1;
|
||||
--yellow-transparent-50: #f9e2af;
|
||||
*/
|
||||
--blue-transparent: color-mix(in srgb, var(--blue), transparent 80%);
|
||||
|
||||
--lavender: #7287fd;
|
||||
--accent: var(--lavender);
|
||||
--lavender-transparent: color-mix(in srgb, var(--lavender), transparent 80%);
|
||||
--accent-transparent-80: color-mix(in srgb, var(--accent), transparent 80%);
|
||||
--accent-transparent-50: color-mix(in srgb, var(--accent), transparent 50%);
|
||||
--accent-transparent: var(--accent-transparent-80);
|
||||
|
|
|
@ -313,3 +313,18 @@ div[role="menu"] div[role="menuitem"]:last-child button {
|
|||
background-color: var(--surface-0);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.banner {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
div.banner.warning {
|
||||
background-color: var(--yellow-transparent);
|
||||
color: var(--yellow);
|
||||
}
|
||||
|
||||
div.banner.info {
|
||||
background-color: var(--lavender-transparent);
|
||||
color: var(--lavender);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import type { SetUsernameJson } from '../models/SetUsernameJson';
|
|||
import type { TeamIntegrationSchema } from '../models/TeamIntegrationSchema';
|
||||
import type { TeamInviteSchema } from '../models/TeamInviteSchema';
|
||||
import type { TeamInviteSchemaList } from '../models/TeamInviteSchemaList';
|
||||
import type { TeamSchema } from '../models/TeamSchema';
|
||||
import type { UpdateEventJson } from '../models/UpdateEventJson';
|
||||
import type { ViewAvailablePlayersResponse } from '../models/ViewAvailablePlayersResponse';
|
||||
import type { ViewScheduleResponse } from '../models/ViewScheduleResponse';
|
||||
|
@ -458,6 +459,30 @@ export class DefaultService {
|
|||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* update_team <PATCH>
|
||||
* @param teamId
|
||||
* @param requestBody
|
||||
* @returns TeamSchema OK
|
||||
* @throws ApiError
|
||||
*/
|
||||
public updateTeam(
|
||||
teamId: number,
|
||||
requestBody?: CreateTeamJson,
|
||||
): CancelablePromise<TeamSchema> {
|
||||
return this.httpRequest.request({
|
||||
method: 'PATCH',
|
||||
url: '/api/team/id/{team_id}/',
|
||||
path: {
|
||||
'team_id': teamId,
|
||||
},
|
||||
body: requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: `Unprocessable Content`,
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* consume_invite <POST>
|
||||
* @param teamId
|
||||
|
|
|
@ -2,7 +2,7 @@ import { defineStore } from "pinia";
|
|||
import { reactive, type Reactive } from "vue";
|
||||
import { useClientStore } from "./client";
|
||||
import { useAuthStore } from "./auth";
|
||||
import { type TeamSchema, type RoleSchema, type ViewTeamMembersResponse } from "@/client";
|
||||
import { type TeamSchema, type RoleSchema, type ViewTeamMembersResponse, type CreateTeamJson } from "@/client";
|
||||
|
||||
export type TeamMap = { [id: number]: TeamSchema };
|
||||
|
||||
|
@ -55,6 +55,11 @@ export const useTeamsStore = defineStore("teams", () => {
|
|||
});
|
||||
}
|
||||
|
||||
async function updateTeam(teamId: number, args: CreateTeamJson) {
|
||||
return await client.default.updateTeam(teamId, args)
|
||||
.then((response) => teams[teamId] = response);
|
||||
}
|
||||
|
||||
async function updateRoles(teamId: number, playerId: string, roles: RoleSchema[]) {
|
||||
return await client.default.editMemberRoles(teamId.toString(), playerId, { roles });
|
||||
}
|
||||
|
@ -70,6 +75,7 @@ export const useTeamsStore = defineStore("teams", () => {
|
|||
fetchTeam,
|
||||
fetchTeamMembers,
|
||||
createTeam,
|
||||
updateTeam,
|
||||
updateRoles,
|
||||
leaveTeam,
|
||||
};
|
||||
|
|
|
@ -75,6 +75,13 @@ function createTeam() {
|
|||
past the hour.
|
||||
</em>
|
||||
</div>
|
||||
<div class="form-group margin">
|
||||
<div class="banner info">
|
||||
<i class="bi bi-info-circle" />
|
||||
Note: changing the timezone or minute offset after team creation
|
||||
will remove all team members' availability data.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group margin">
|
||||
<div class="action-buttons">
|
||||
<button class="accent" @click="createTeam">Create team</button>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { useTeamSettings } from '@/composables/team-settings';
|
||||
import { useTeamSettings } from "@/composables/team-settings";
|
||||
import timezones from "@/assets/timezones.json";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useTeamsStore } from "@/stores/teams";
|
||||
import { useTeamDetails } from "@/composables/team-details";
|
||||
import { computed } from "@vue/reactivity";
|
||||
|
||||
const {
|
||||
teamName,
|
||||
|
@ -8,9 +12,61 @@ const {
|
|||
minuteOffset,
|
||||
} = useTeamSettings();
|
||||
|
||||
function updateTeamSettings() {
|
||||
const { teamId } = useTeamDetails();
|
||||
|
||||
function updateTeamSettings() {
|
||||
teamsStore.updateTeam(teamId.value, {
|
||||
teamName: teamName.value,
|
||||
leagueTimezone: timezone.value,
|
||||
minuteOffset: minuteOffset.value,
|
||||
});
|
||||
}
|
||||
|
||||
function resetChanges() {
|
||||
teamName.value = team.value.teamName;
|
||||
timezone.value = team.value.tzTimezone;
|
||||
minuteOffset.value = team.value.minuteOffset;
|
||||
}
|
||||
|
||||
const hasChangedDetails = computed(() => {
|
||||
if (!team) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
teamName.value !== team.value.teamName ||
|
||||
timezone.value !== team.value.tzTimezone ||
|
||||
minuteOffset.value !== team.value.minuteOffset
|
||||
);
|
||||
});
|
||||
|
||||
const hasChangedTimeDetails = computed(() => {
|
||||
if (!team) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
timezone.value !== team.value.tzTimezone ||
|
||||
minuteOffset.value !== team.value.minuteOffset
|
||||
);
|
||||
});
|
||||
|
||||
const isLoaded = ref(false);
|
||||
|
||||
const teamsStore = useTeamsStore();
|
||||
|
||||
const team = computed(() => teamsStore.teams[teamId.value]);
|
||||
|
||||
onMounted(() => {
|
||||
isLoaded.value = true;
|
||||
teamsStore.fetchTeam(teamId.value)
|
||||
.then((response) => {
|
||||
teamName.value = response.team.teamName;
|
||||
timezone.value = response.team.tzTimezone;
|
||||
minuteOffset.value = response.team.minuteOffset;
|
||||
isLoaded.value = false;
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -53,11 +109,25 @@ function updateTeamSettings() {
|
|||
past the hour.
|
||||
</em>
|
||||
</div>
|
||||
<div class="form-group margin" v-if="hasChangedTimeDetails">
|
||||
<div class="banner warning">
|
||||
<i class="bi bi-exclamation-triangle-fill margin"></i>
|
||||
Warning: changing the timezone or minute offset will remove all
|
||||
current availability data.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group margin">
|
||||
<div class="action-buttons">
|
||||
<button class="transparent" v-if="hasChangedDetails" @click="resetChanges">
|
||||
<i class="bi bi-arrow-counterclockwise"></i>
|
||||
Undo changes
|
||||
</button>
|
||||
<button class="accent" @click="updateTeamSettings">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
|
|
@ -10,7 +10,7 @@ from models.player_team import PlayerTeam
|
|||
from models.player_team_availability import PlayerTeamAvailability
|
||||
from models.player_team_role import PlayerTeamRole, RoleSchema
|
||||
from models.team import Team, TeamSchema
|
||||
from middleware import requires_authentication
|
||||
from middleware import assert_team_authority, requires_authentication, requires_team_membership
|
||||
from spec import spec, BaseModel
|
||||
from team_invite import api_team_invite
|
||||
from team_integration import api_team_integration
|
||||
|
@ -86,6 +86,27 @@ def create_team(json: CreateTeamJson, player: Player, **kwargs):
|
|||
response = ViewTeamResponse(team=TeamSchema.from_model(team))
|
||||
return response.dict(by_alias=True), 200
|
||||
|
||||
@api_team.patch("/id/<int:team_id>/")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamSchema,
|
||||
),
|
||||
operation_id="update_team",
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership()
|
||||
def update_team(player_team: PlayerTeam, team_id: int, json: CreateTeamJson, **kwargs):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
team = player_team.team
|
||||
team.team_name = json.team_name
|
||||
team.tz_timezone = json.league_timezone
|
||||
team.minute_offset = json.minute_offset
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return TeamSchema.from_model(team).dict(by_alias=True), 200
|
||||
|
||||
@api_team.delete("/id/<team_id>/")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
|
|
Loading…
Reference in New Issue