複数のメールマガジンを一度に登録・解除するページを作成する
概要
MagazineInfo::list
のエンドポイントにself_onlyのパラメータを設定して利用すると自身の購読している配信の一覧が取得できます。
本チュートリアルではこちらを利用して、複数のメールマガジンとその購読状態が表示され、一度に登録・解除できるページを作成します。
学べること
以下の手順で階層構造を持ったコメントの追加と取得をします。
前提条件
このページはKurocoとNuxt.jsでのプロジェクトが構築済みであり、ログイン画面の実装がされていることを前提としています。
まだ構築していない場合は、下記のチュートリアルを参照してください。
Kurocoビギナーズガイド
KurocoとNuxt.jsで、ログイン画面を構築する
本チュートリアルでは以下のバージョンでコードを書いています。
Nuxt2: v2.15.8
Nuxt3: v3.8.0
複数の配信を準備する
まずはKurocoの管理画面で複数の配信を登録します。
[キャンペーン]->[配信]で配信一覧に遷移し、右上の[追加]をクリックして配信を登録します。
今回は以下のように3つの配信を準備しました。
配信のIDはエンドポイントに設定するのでメモしてください。
エンドポイントを設定する
エンドポイントは Login::login_challenge のエンドポイントが設定されたAPI設定に追加します。
そうすることでログインした認証情報を利用してエンドポイントへのリクエストが行われます。
異なるAPI間で認証情報は共有できませんので注意してください。
今回は自身の購読している配信一覧を取得するエンドポイントと、配信登録するエンドポイント、配信解除するエンドポイントの3つを設定します。
[新しいエンドポイントの追加]をクリックして、それぞれ作成します。
配信一覧を取得するエンドポイント
項目 | 設定内容 |
---|---|
パス | my_magazine/info |
カテゴリー | マガジン |
モデル | MagazineInfo |
オペレーション | list |
magazine_id | レスポンスの対象となる配信IDを入力する 7 8 9 |
self_only | チェックを入れる |
self_onlyを有効にすると、購読している配信のみレスポンスされます。
購読有無によらない配信の一覧をAPIから取得する場合は、self_onlyを付与しないMagazineInfo::list
のエンドポイントを別途作成して利用してください。
配信登録するエンドポイント
項目 | 設定内容 |
---|---|
パス | magazine/subscribe |
カテゴリー | マガジン |
モデル | MagazineSubscriber |
オペレーション | subscribe |
allow_magazine_id | エンドポイントを利用して購読者登録を許可する配信IDを入力する 7 8 9 |
self_only | チェックを入れる |
self_onlyにチェックが無い場合、エンドポイントが分かれば他人を購読者に追加できてしまうのでご注意ください。
allow_magazine_idの指定が無い場合、全ての配信に対して購読者登録できてしまうのでご注意ください。
配信解除するエンドポイント
項目 | 設定内容 |
---|---|
パス | magazine/unsubscribe |
カテゴリー | マガジン |
モデル | MagazineSubscriber |
オペレーション | unsubscribe |
allow_magazine_id | エンドポイントを利用して購読解除を許可する配信IDを入力する 7 8 9 |
self_only | チェックを入れる |
self_onlyにチェックが無い場合、エンドポイントが分かれば他人の購読者登録を削除できてしまうのでご注意ください。
allow_magazine_idの指定が無い場合、全ての配信に対して購読者登録の削除ができてしまうのでご注意ください。
本チュートリアルでは利用していませんがMagazineSubscriber::listのエンドポイントを利用すると、配信に対する購読者の一覧が取得できます。
search_mail_address contains "@example.com"
のようにフィルタをかけるとメールアドレスのドメイン名で検索が可能です。
管理者向けの管理画面を実装する場合にご活用ください。
フロントエンドを実装する
以下のファイルを作成します。
- Nuxt2
- Nuxt3
<template>
<div>
<h1>Update mail magazine</h1>
<form>
<p v-if="resultMessage !== null" style="color:green">{{ resultMessage }}</p>
<div v-for="magazine in magazines" :key="magazine.id">
<h2>{{ magazine.label }}</h2>
<input type="radio" :id="`s-${magazine.id}`" :value="{ 'status': 'subscribe', 'id': magazine.id }"
v-model="submitData[magazine.key]" @change="handleChange(magazine.key)" />
<label :for="`s-${magazine.id}`">Subscribe</label>
<input type="radio" :id="`u-${magazine.id}`" :value="{ 'status': 'unsubscribe', 'id': magazine.id }"
v-model="submitData[magazine.key]" @change="handleChange(magazine.key)" />
<label :for="`u-${magazine.id}`">Unsubscribe</label>
</div>
</form>
</div>
</template>
<script>
export default {
middleware: 'auth',
data() {
return {
resultMessage: null,
submitData: {
news: { 'status': 'unsubscribe', 'id': 7 },
sale: { 'status': 'unsubscribe', 'id': 8 },
event: { 'status': 'unsubscribe', 'id': 9 },
},
magazines: [
{ id: 7, key: 'news', label: 'Announcement of the Latest Release' },
{ id: 8, key: 'sale', label: 'Notification of Exclusive Sale' },
{ id: 9, key: 'event', label: 'Announcement of the Latest Release' },
],
};
},
async asyncData({ $axios }) {
return {
response: await $axios.$get('/rcms-api/18/my_magazine/info'),
};
},
created() {
//Reflect Subscription Status Upon Access
if (this.response && this.response.list) {
this.response.list.forEach((magazineInfo) => {
const matchingMagazine = this.magazines.find(magazine => magazine.id === magazineInfo.magazine_id);
if (matchingMagazine) {
const key = matchingMagazine.key;
this.$set(this.submitData, key, { 'status': 'subscribe', 'id': magazineInfo.magazine_id });
}
});
}
},
methods: {
async handleChange(magazineKey) {
try {
await this.$axios.$post(
`/rcms-api/18/magazine/${this.submitData[magazineKey].status}/${this.submitData[magazineKey].id}`,
{ member_id: this.$store.state.profile.member_id }
);
this.resultMessage = 'Data submitted successfully';
} catch (error) {
this.resultMessage = 'Error submitting data';
console.error(error);
}
},
},
};
</script>
<template>
<div v-if="response">
<h1>Update mail magazine</h1>
<form>
<p v-if="resultMessage !== null" style="color:green">{{ resultMessage }}</p>
<div v-for="magazine in magazines" :key="magazine.id">
<h2>{{ magazine.label }}</h2>
<input type="radio" :id="`s-${magazine.id}`" :value="{ status: 'subscribe', id: magazine.id }"
v-model="submitData[magazine.key]" @change="handleChange(magazine.key)" />
<label :for="`s-${magazine.id}`">Subscribe</label>
<input type="radio" :id="`u-${magazine.id}`" :value="{ status: 'unsubscribe', id: magazine.id }"
v-model="submitData[magazine.key]" @change="handleChange(magazine.key)" />
<label :for="`u-${magazine.id}`">Unsubscribe</label>
</div>
</form>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useProfileStore } from '~/composables/profile';
definePageMeta({
middleware: "auth",
});
const config = useRuntimeConfig();
const resultMessage = ref(null);
const submitData = ref({
news: { status: "unsubscribe", id: 7 },
sale: { status: "unsubscribe", id: 8 },
event: { status: "unsubscribe", id: 9 },
});
const magazines = ref([
{ id: 7, key: "news", label: "Announcement of the Latest Release" },
{ id: 8, key: "sale", label: "Notification of Exclusive Sale" },
{ id: 9, key: "event", label: "Announcement of the Latest Release" },
]);
const response = ref(null);
const { profile } = useProfileStore();
const getData = async () => {
try {
response.value = await $fetch("/rcms-api/18/my_magazine/info", {
credentials: "include",
baseURL: config.public.apiBase,
});
} catch (error) {
resultMessage.value = "Error fetching data";
console.log(error);
}
//Reflect Subscription Status Upon Access
if (response.value && response.value.list) {
response.value.list.forEach((magazineInfo) => {
const matchingMagazine = magazines.value.find(
(magazine) => magazine.id === magazineInfo.magazine_id
);
if (matchingMagazine) {
const key = matchingMagazine.key;
submitData.value[key] = {
status: "subscribe",
id: magazineInfo.magazine_id,
};
}
});
}
};
const handleChange = async (magazineKey) => {
try {
await $fetch(
`/rcms-api/18/magazine/${submitData.value[magazineKey].status}/${submitData.value[magazineKey].id}`,
{
method: "POST",
credentials: "include",
baseURL: config.public.apiBase,
body: { member_id: profile.value.member_id },
}
);
resultMessage.value = "Data submitted successfully";
} catch (error) {
resultMessage.value = "Error submitting data";
console.error(error);
}
};
await getData();
</script>
今回はサンプルとしてラジオボタンで購読状態を表示し、変更があった場合は変更があったタイミングですぐにAPIリクエストを送信する実装としました。
Sumbitボタンを付けて、Submit時にまとめてPOSTのリクエストを送る場合は、配信の数が増えると処理に時間がかかる場合があります。
変更のない配信へのリクエストを省略したり、新しい購読状態をバッチに登録させて処理させるなどの工夫をしてください。
動作の確認をする
ログイン後に対象のディレクトリにアクセスすると、配信の一覧が表示され、購読状態を更新したタイミングでAPIリクエストが送信されることを確認できます。
関連ドキュメント
サポート
お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。