petra-tool / frontend / src / components / Register.vue
Register.vue
Raw
<template>
  <v-dialog
    v-model="dialog"
    @click:outside="onClose"
    max-width="900"
    overlay-color="white"
    content-class="rounded-xl"
  >
    <template v-slot:activator="{ on, attrs }">
      <v-btn depressed dark color="grey"
             @click="dialog = true" block
             v-bind="attrs"
             v-on="on">
        Register
      </v-btn>
    </template>

    <dialog-alert v-on:on-cancel="onClose" v-on:on-continue="onClose" v-if="registrationDisabled">
      <template v-slot:title>Registration Disabled</template>
      <template v-slot:text>
        Registration is currently disabled by the Administrator!
        <v-form v-show="false" ref="form" v-model="form.valid" lazy-validation></v-form>
        <v-form v-show="false" ref="formMembers" v-model="form.validMembers" lazy-validation></v-form>
      </template>
    </dialog-alert>

    <v-card v-else>
      <v-card-title class="accent white--text pt-10 pb-4 text-h5 pl-9">
        Register
      </v-card-title>
      <v-tabs v-model="tab" dark background-color="accent" fixed-tabs>
        <v-tab class="body-1">1. Create Team</v-tab>
        <v-tab class="body-1">2. Define Cycle Duration</v-tab>
        <v-tab class="body-1">3. Define Roles</v-tab>
        <v-tab class="body-1">4. Register Team</v-tab>
      </v-tabs>
      <v-card-text>
        <v-container fluid>
          <v-tabs-items v-model="tab" touchless>
            <v-tab-item eager>
              <v-form ref="form" v-model="form.valid" lazy-validation>
                <v-row no-gutters>
                  <v-col cols="12">
                    <div class="text-h5 text--primary mb-3">Log In</div>
                    <v-text-field
                      label="Teamname"
                      v-model="form.teamname"
                      dense
                      :disabled="registrationSuccess"
                      outlined
                      counter maxlength="64"
                      :rules="[value => !!value || 'Teamname is required.']"
                    ></v-text-field>
                  </v-col>
                  <v-col cols="12">
                    <div class="text-h5 text--primary mb-3">Password</div>
                    <v-text-field
                      label="Password"
                      dense
                      :disabled="registrationSuccess"
                      v-model="form.password"
                      :append-icon="form.show ? 'mdi-eye' : 'mdi-eye-off'"
                      :type="form.show ? 'text' : 'password'"
                      @click:append="form.show = !form.show"
                      outlined
                      :rules="[value => !!value || 'Password is required.']"
                    ></v-text-field>
                  </v-col>
                  <v-col cols="12">
                    <div class="text-h5 text--primary mb-3">Confirm Password</div>
                    <v-text-field
                      label="Confirm Password"
                      dense
                      :disabled="registrationSuccess"
                      v-model="form.password2"
                      :append-icon="form.show ? 'mdi-eye' : 'mdi-eye-off'"
                      :type="form.show ? 'text' : 'password'"
                      @click:append="form.show = !form.show"
                      outlined
                      :rules="[value => !!value || 'Confirmation password is required.',
                         value => value === form.password || 'Password confirmation does not match.']"
                    ></v-text-field>
                  </v-col>
                </v-row>
              </v-form>
            </v-tab-item>
            <v-tab-item eager>
              <v-row>
                <v-col cols="12" class="text--primary caption-2 my-5">
                  Cycles are time-bound development periods, ranging from 1 day to 3 weeks. 
                  Teams focus on specific sub-phases for building prototypes to test hypotheses. 
                  You can run more than one cycle according to your needs. 
                  For shorter projects like hackathons, opt for one-day cycle, while longer projects benefit from 1 to 3-week durations. 
                  Keep in mind that duration changes are only allowed when no active cycles are ongoing.
                </v-col>
                <v-col cols="12">
                  <div class="text-h5 text--primary mb-3">Cycle Duration</div>
                  <v-select
                    label="Select Cycle Duration"
                    dense
                    :items="form.sprintOptions"
                    v-model="form.sprint"
                    :disabled="registrationSuccess"
                    item-value="value"
                    outlined
                    :rules="[value => !!value || 'Value is required.']"
                  ></v-select>
                </v-col>
              </v-row>

            </v-tab-item>
            <v-tab-item eager>
              <v-row>
                <v-col cols="12" class="text--primary caption-2 my-5">
                  The team collaboration is enhanced by providing predefined accountabilities within PETRA. It is recommended to assign each role, but roles can be assigned multiple
                  times (e.g., two Architects, three Component Designer, etc.). The following roles may be selected:
                  <ul>
                    <li><b>Project Manager (PM)</b> oversees workflow and ensures effective project management within the team.
                        </li>
                        <li><b>Problem Role (PR)</b> focuses on understanding user needs and ensuring product desirability.
                        </li>
                        <li><b>Tech Role (TR)</b> develops technically feasible solutions for the project.
                        </li>
                        <li><b>Business Role (BR)</b> analyzes the market and develops the project's business model.
                        </li>
                  </ul>
                </v-col>
              </v-row>
              <v-form ref="formMembers" v-model="form.validMembers" lazy-validation>
                <v-row>
                  <v-col cols="12" md="4">
                    <div class="text-h5 text--primary mb-3">Add Team Member</div>
                    <v-text-field
                      label="Type Name"
                      dense
                      :disabled="registrationSuccess"
                      v-model="form.name"
                      outlined
                      counter maxlength="64"
                      :rules="[value => !!value || 'Name is required.',
                      value => form.members.filter(member => member.name === value).length === 0 || 'Name already exists.']"
                    ></v-text-field>
                  </v-col>
                  <v-col cols="12" md="4">
                    <div class="text-h5 text--primary mb-3">Role</div>
                    <v-select
                      label="Select Role"
                      dense
                      :disabled="registrationSuccess"
                      :items="form.roleOptions"
                      v-model="form.roleSelected"
                      item-text="text"
                      return-object
                      outlined
                      :rules="[value => !!value || 'Role is required.']"
                    ></v-select>
                  </v-col>
                  <v-col cols="12" md="4">
                    <div class="text-h5 text--primary mb-3">Working Hours on Average</div>
                    <v-select
                      label="Select Working Hours"
                      dense
                      :disabled="registrationSuccess"
                      :items="form.hoursOptions"
                      v-model="form.hoursSelected"
                      return-object
                      outlined
                      :rules="[value => !!value || 'Value is required.']"
                    ></v-select>
                  </v-col>
                  <v-col cols="12" class="text-right">
                    <v-btn color="primary"
                           depressed
                           :disabled="registrationSuccess"
                           @click="addMember">
                      Add Member
                    </v-btn>
                  </v-col>
                  <v-col cols="12" v-for="(member, k) in form.members" :key="k"
                         class="text-body-1 text--primary mb-2">
                    <v-avatar
                      :color="colors[k % 4]"
                      size="36"
                      class="mr-3 text-uppercase white--text body-2"
                    >{{ member.name.substr(0, 2) }}
                    </v-avatar>
                    {{ member.name }} - {{ member.role.text }} - {{ member.workingHours }}h

                    <v-btn
                      icon
                      color="gray"
                      class="ml-5"
                      :disabled="registrationSuccess"
                      @click="deleteMember(k)">
                      <v-icon>mdi-delete</v-icon>
                    </v-btn>
                  </v-col>
                </v-row>
              </v-form>
            </v-tab-item>
            <v-tab-item eager>
              <v-row>
                <v-col cols="12" md="6">
                  <div class="text-h5 text--primary">Summary</div>
                  <v-row>
                    <v-col cols="12">
                      <div class="text-body-1 font-weight-bold text--primary">Name</div>
                      <div class="">{{ form.teamname }}</div>
                    </v-col>
                    <v-col cols="12">
                      <div class="text-body-1 font-weight-bold text--primary">Team</div>
                      <div class="" v-for="(member, k) in form.members" :key="k">
                        {{ member.name }} - {{ member.role.text }} - {{ member.workingHours }}h
                      </div>
                    </v-col>
                  </v-row>
                </v-col>
                <v-col cols="12" md="6">
                  <v-expand-transition>
                    <v-alert outlined color="primary" class="ma-6" v-show="registrationSuccess">
                      <v-card class="" flat>
                        <v-card-text class="text-center pt-10 pb-0">
                          <v-icon size="75" color="accent">mdi-information-outline</v-icon>
                        </v-card-text>
                        <v-card-title class="text-h5 justify-center">
                          Thank you for registering your Team!
                        </v-card-title>
                        <v-card-text class="text-center pb-10 text--primary">
                          Please contact the administrator (<a href="mailto:petra.lpl@ed.tum.de">petra.lpl@ed.tum.de</a>) to enable your dashboard.
                        </v-card-text>
                      </v-card>
                    </v-alert>
                  </v-expand-transition>
                </v-col>
              </v-row>
            </v-tab-item>
          </v-tabs-items>
        </v-container>
      </v-card-text>
      <v-card-actions class="pa-10">
        <v-btn
          text
          @click="onClose"
        >
          Cancel
        </v-btn>
        <v-spacer></v-spacer>
        <v-btn v-if="tab < 3"
               color="primary"
               depressed
               min-width="150"
               @click="tab += 1"
        >Continue
        </v-btn>
        <v-btn v-else-if="registrationSuccess"
               color="primary"
               depressed
               min-width="150"
               @click="onClose()">
          Exit
        </v-btn>
        <v-btn v-else
               color="primary"
               depressed
               min-width="150"
               :loading="loading"
               @click="onSubmit"
        >
          Register
        </v-btn>
      </v-card-actions>
    </v-card>

    <v-dialog
      v-model="dialogError"
      max-width="500px"
      overlay-color="white"
      style="z-index: 99"
    >
      <dialog-alert v-on:on-cancel="dialogError = false" v-on:on-continue="dialogError = false">
        <template v-slot:title>Registration Error</template>
        <template v-slot:text>
          <div v-if="Object.keys(errors).length > 0">
            <p v-for="(error, i) in errors" :key="i">{{ error }}</p>
          </div>
          <div v-else>
            Some fields are not valid. Fix errors to continue!
          </div>
        </template>
      </dialog-alert>
    </v-dialog>

  </v-dialog>
</template>

<script>
import DialogAlert from "@/components/DialogAlert";

export default {
  name: "Register",
  components: {DialogAlert},
  data: () => ({
    dialog: false,
    tab: null,
    dialogError: null,
    form: {
      teamname: '',
      password: '',
      password2: '',
      show: false,
      members: [],
      name: '',
      roleOptions: [{
        text: 'Project Manager (PM)',
        value: 'pm'
      }, {
        text: 'Problem Role (PR)',
        value: 'pr'
      }, {
        text: 'Tech Role (TR)',
        value: 'tr'
      }, {
        text: 'Business Role (BR)',
        value: 'br'
      }],
      roleSelected: '',
      rolesLongTerm: false,
      hoursOptions: [10, 20, 40],
      hoursSelected: '',
      sprintOptions: [
        {text: '0.2 Weeks (1 Day)', value: 0.2},
        {text: '0.6 Weeks (3 Days)', value: 0.6},
        {text: '1 Week (5 Days)', value: 1},
        {text: '2 Weeks (10 Days)', value: 2},
        {text: '3 Weeks (15 Days)', value: 3},
      ],
      sprint: '',
    },
    valid: true,
    validMembers: true,
    errors: {},
    remember: false,
    staySignedIn: true,
    fetchUser: true, // fixed i.e. always load team data from database (required)
    autoLogin: false, // registrations have to be approved by the admin i.e. login does not work & don't forget to enable tokens in /register endpoint
    loading: false,
    registrationSuccess: false,

    colors: ["error", "secondary", "primary", "info",],

    registrationDisabled: false,
    waitingForApproval: false,
  }),
  methods: {
    parse_errors(res) {
      this.errors = Object.fromEntries(res.data.errors.map(item => [item.field, item.msg]))
    },
    addMember() {
      if (this.$refs.formMembers.validate()) {
        this.form.members.push({
          name: this.form.name,
          role: this.form.roleSelected,
          workingHours: this.form.hoursSelected
        })
        this.form.name = ''
        this.form.roleSelected = null
        this.$refs.formMembers.reset()
      }
    },
    deleteMember(k) {
      this.form.members.splice(k, 1)
    },
    onSubmit() {
      this.errors = {}

      if (this.$refs.form.validate()) {
        this.loading = true;

        this.$store.dispatch('auth/register', {
          data: this.form,
          remember: this.remember,
          fetchUser: this.fetchUser,
          autoLogin: this.autoLogin,
          staySignedIn: this.staySignedIn,
        })
          .then(() => {
            // Success
            this.registrationSuccess = true;
          }, (res) => {
            // Error
            this.parse_errors(res.response)
            this.dialogError = true;
          })
      } else {
        this.dialogError = true
      }
      this.loading = false
    },
    onClose() {
      this.dialog = false
      this.$refs.form.reset()
      this.$refs.formMembers.reset()
      this.registrationSuccess = false;
      this.errors = {}
      this.form.members = []
      this.tab = null
    }
  },
  async created() {
    await this.$http.get('/settings', {}).then(res => {
      let settings = res.data.settings;

      this.registrationDisabled = !!settings.reg

    })

  }
}
</script>

<style scoped>

</style>