<commit_before><template>
  <app-a11y-dialog
    id="help-wanted"
    ref="dialog"
    :cancellable="state !== `loading`"
    :shown="context !== null"
    :title="title"
    @hide="onHide">

    <form v-if="state === `ready` && context !== null" action="#" @submit.prevent="onSubmit">
      <app-labeled-value
        v-if="location !== null"
        :value="location"
        label="Location" />

      <app-labeled-value
        v-if="context.helpWanted !== null"
        label="Problem description">
        <span v-html="context.helpWanted" />
      </app-labeled-value>

      <app-labeled-input name="message" label="Message">
        <textarea v-model="message" name="message" />
      </app-labeled-input>

      <app-labeled-input
        name="github-username"
        label="GitHub username"
        hint="If you want to be mentioned in the issue.">
        <input v-model="githubUsername" type="text" name="github-username">
      </app-labeled-input>

      <div class="button-bar right">
        <button :disabled="message === ``" type="submit" class="primary">Send information</button>
      </div>
    </form>

    <template v-else-if="state === `loading`">
      Uploading…
    </template>

    <template v-else-if="state === `success`">
      Your information was successfully uploaded to GitHub (see the <a :href="issueUrl" target="_blank">issue</a>). The fixture will be updated as soon as your information has been reviewed. Thank you for your contribution!

      <div class="button-bar right">
        <a href="#" class="button secondary" @click.prevent="hide">Close</a>
        <a :href="issueUrl" class="button primary" target="_blank">See issue</a>
      </div>
    </template>

    <template v-else-if="state === `error`">
      <span>Unfortunately, there was an error while uploading. Please copy the following data and manually submit it.</span>

      <textarea :value="errorData" readonly />

      <div class="button-bar right">
        <a href="#" class="button secondary" @click.prevent="hide">Close</a>
        <a :href="mailtoUrl" class="button secondary" target="_blank">Send email</a>
        <a href="https://github.com/OpenLightingProject/open-fixture-library/issues/new" class="button primary" target="_blank">Create issue on GitHub</a>
      </div>
    </template>

  </app-a11y-dialog>
</template>

<script>
import a11yDialogVue from '~/components/a11y-dialog.vue';

import labeledInputVue from '~/components/labeled-input.vue';
import labeledValueVue from '~/components/labeled-value.vue';

export default {
  components: {
    'app-a11y-dialog': a11yDialogVue,
    'app-labeled-input': labeledInputVue,
    'app-labeled-value': labeledValueVue
  },
  model: {
    prop: `context`
  },
  props: {
    type: {
      type: String,
      required: true
    },
    context: {
      type: Object,
      default: null
    }
  },
  data: () => {
    return {
      state: `ready`,
      message: ``,
      githubUsername: ``,
      issueUrl: null,
      error: null
    };
  },
  computed: {
    title() {
      if (this.state === `loading`) {
        return `Sending your message…`;
      }

      if (this.state === `success`) {
        return `Message sent`;
      }

      if (this.state === `error`) {
        return `Failed to send message`;
      }

      return `Improve ${this.type === `plugin` ? `plugin` : `fixture`}`;
    },
    location() {
      if (this.type === `capability`) {
        const cap = this.context;
        const channel = cap._channel;
        return `Channel "${channel.key}" → Capability "${cap.name}" (${cap.rawDmxRange})`;
      }

      return null;
    },
    fixture() {
      if (this.type === `fixture`) {
        return this.context;
      }

      if (this.type === `capability`) {
        return this.context._channel.fixture;
      }

      return null;
    },
    sendObject() {
      const sendObject = {
        type: this.type,
        location: this.location,
        helpWanted: this.context.helpWanted,
        message: this.message,
        githubUsername: this.githubUsername !== `` ? this.githubUsername : null
      };

      if (this.type === `plugin`) {
        sendObject.context = this.context.key;
      }
      else {
        const manKey = this.fixture.manufacturer.key;
        const fixKey = this.fixture.key;

        sendObject.context = `${manKey}/${fixKey}`;
      }

      return sendObject;
    },
    errorData() {
      return `${JSON.stringify(this.sendObject, null, 2)}\n\n${this.error}`;
    },
    mailtoUrl() {
      const subject = `Feedback for fixture '${this.sendObject.manKey}/${this.sendObject.fixKey}'`;

      const mailBodyData = {
        'Problem location': this.location,
        'Problem description': this.context.helpWanted,
        'Message': this.message
      };

      const body = Object.entries(mailBodyData).filter(
        ([key, value]) => value !== null
      ).map(
        ([key, value]) => `${key}:${value.includes(`\n`) ? `\n` : ` `}${value}`
      ).join(`\n`);

      return `mailto:<EMAIL>?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
    }
  },
  methods: {
    async onSubmit() {
      this.state = `loading`;

      try {
        const response = await this.$axios.post(`/ajax/submit-feedback`, this.sendObject);

        if (response.data.error) {
          throw new Error(response.data.error);
        }

        this.issueUrl = response.data.issueUrl;
        this.state = `success`;
      }
      catch (error) {
        console.error(`There was a problem with the request.`, error);
        this.error = error.message;
        this.state = `error`;
      }
    },
    hide() {
      this.$refs.dialog.$emit(`hide`);
    },
    onHide() {
      if (this.state === `success`) {
        this.message = ``;
      }

      this.state = `ready`;
      this.issueUrl = null;
      this.error = null;
      this.$emit(`input`, null);
    }
  }
};
</script>
<commit_msg>Fix helpWanted dialog mailto URL (#993)<commit_after><template>
  <app-a11y-dialog
    id="help-wanted"
    ref="dialog"
    :cancellable="state !== `loading`"
    :shown="context !== null"
    :title="title"
    @hide="onHide">

    <form v-if="state === `ready` && context !== null" action="#" @submit.prevent="onSubmit">
      <app-labeled-value
        v-if="location !== null"
        :value="location"
        label="Location" />

      <app-labeled-value
        v-if="context.helpWanted !== null"
        label="Problem description">
        <span v-html="context.helpWanted" />
      </app-labeled-value>

      <app-labeled-input name="message" label="Message">
        <textarea v-model="message" name="message" />
      </app-labeled-input>

      <app-labeled-input
        name="github-username"
        label="GitHub username"
        hint="If you want to be mentioned in the issue.">
        <input v-model="githubUsername" type="text" name="github-username">
      </app-labeled-input>

      <div class="button-bar right">
        <button :disabled="message === ``" type="submit" class="primary">Send information</button>
      </div>
    </form>

    <template v-else-if="state === `loading`">
      Uploading…
    </template>

    <template v-else-if="state === `success`">
      Your information was successfully uploaded to GitHub (see the <a :href="issueUrl" target="_blank">issue</a>). The fixture will be updated as soon as your information has been reviewed. Thank you for your contribution!

      <div class="button-bar right">
        <a href="#" class="button secondary" @click.prevent="hide">Close</a>
        <a :href="issueUrl" class="button primary" target="_blank">See issue</a>
      </div>
    </template>

    <template v-else-if="state === `error`">
      <span>Unfortunately, there was an error while uploading. Please copy the following data and manually submit it.</span>

      <textarea :value="errorData" readonly />

      <div class="button-bar right">
        <a href="#" class="button secondary" @click.prevent="hide">Close</a>
        <a :href="mailtoUrl" class="button secondary" target="_blank">Send email</a>
        <a href="https://github.com/OpenLightingProject/open-fixture-library/issues/new" class="button primary" target="_blank">Create issue on GitHub</a>
      </div>
    </template>

  </app-a11y-dialog>
</template>

<script>
import a11yDialogVue from '~/components/a11y-dialog.vue';

import labeledInputVue from '~/components/labeled-input.vue';
import labeledValueVue from '~/components/labeled-value.vue';

export default {
  components: {
    'app-a11y-dialog': a11yDialogVue,
    'app-labeled-input': labeledInputVue,
    'app-labeled-value': labeledValueVue
  },
  model: {
    prop: `context`
  },
  props: {
    type: {
      type: String,
      required: true
    },
    context: {
      type: Object,
      default: null
    }
  },
  data: () => {
    return {
      state: `ready`,
      message: ``,
      githubUsername: ``,
      issueUrl: null,
      error: null
    };
  },
  computed: {
    title() {
      if (this.state === `loading`) {
        return `Sending your message…`;
      }

      if (this.state === `success`) {
        return `Message sent`;
      }

      if (this.state === `error`) {
        return `Failed to send message`;
      }

      return `Improve ${this.type === `plugin` ? `plugin` : `fixture`}`;
    },
    location() {
      if (this.type === `capability`) {
        const cap = this.context;
        const channel = cap._channel;
        return `Channel "${channel.key}" → Capability "${cap.name}" (${cap.rawDmxRange})`;
      }

      return null;
    },
    fixture() {
      if (this.type === `fixture`) {
        return this.context;
      }

      if (this.type === `capability`) {
        return this.context._channel.fixture;
      }

      return null;
    },
    sendObject() {
      const sendObject = {
        type: this.type,
        location: this.location,
        helpWanted: this.context.helpWanted,
        message: this.message,
        githubUsername: this.githubUsername !== `` ? this.githubUsername : null
      };

      if (this.type === `plugin`) {
        sendObject.context = this.context.key;
      }
      else {
        const manKey = this.fixture.manufacturer.key;
        const fixKey = this.fixture.key;

        sendObject.context = `${manKey}/${fixKey}`;
      }

      return sendObject;
    },
    errorData() {
      return `${JSON.stringify(this.sendObject, null, 2)}\n\n${this.error}`;
    },
    mailtoUrl() {
      const subject = `Feedback for ${this.sendObject.type} '${this.sendObject.context}'`;

      const mailBodyData = {
        'Problem location': this.location,
        'Problem description': this.context.helpWanted,
        'Message': this.message
      };

      const body = Object.entries(mailBodyData).filter(
        ([key, value]) => value !== null
      ).map(
        ([key, value]) => `${key}:${value.includes(`\n`) ? `\n` : ` `}${value}`
      ).join(`\n`);

      return `mailto:<EMAIL>?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
    }
  },
  methods: {
    async onSubmit() {
      this.state = `loading`;

      try {
        const response = await this.$axios.post(`/ajax/submit-feedback`, this.sendObject);

        if (response.data.error) {
          throw new Error(response.data.error);
        }

        this.issueUrl = response.data.issueUrl;
        this.state = `success`;
      }
      catch (error) {
        console.error(`There was a problem with the request.`, error);
        this.error = error.message;
        this.state = `error`;
      }
    },
    hide() {
      this.$refs.dialog.$emit(`hide`);
    },
    onHide() {
      if (this.state === `success`) {
        this.message = ``;
      }

      this.state = `ready`;
      this.issueUrl = null;
      this.error = null;
      this.$emit(`input`, null);
    }
  }
};
</script>

{'fraction_non_alphanumeric': 0.16427311665406905, 'fraction_numerical': 0.0024355421180818006, 'mean_word_length': 2.4307116104868913, 'pattern_counts': {'":': 0, '<': 99, '<?xml version=': 0, '>': 105, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '112950', 'n_tokens_mistral': 3747, 'n_tokens_neox': 3630, 'n_words': 791}