Back to "एक समाचार - पत्र सदस्यता सेवा पीट. 1 - सदस्यता और सदस्यता पृष्ठ"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

Alpine.js ASP.NET Email Newsletter

एक समाचार - पत्र सदस्यता सेवा पीट. 1 - सदस्यता और सदस्यता पृष्ठ

Saturday, 21 September 2024

परिचय

जबकि अन्य लोगों के ब्लॉग से मैंने देखा कि उनमें से बहुतों को सदस्यता सेवा मिली है जो उपयोक्ताों को उस ब्लॉग से हर हफ्ते डाक भेजने की अनुमति देते हैं। मैंने फैसला किया कि मैं इस अनुवाद के अपने ही संस्करण को लागू करूँगा और इसे कैसे करूँ ।

ध्यान दीजिए: मैं उम्मीद नहीं करता कि कोई वास्तव में इस का उपयोग करेगा, मेरे हाथ पर बहुत समय है एक अनुबंध के माध्यम से गिर गया के बाद तो यह मुझे व्यस्त रखता है!

कदम

इसलिए इस सेवा को बनाने के लिए मैंने फैसला किया कि मैं इन माँगों को पूरा करूँगा ।

  1. एक अंतर्निर्मित सब्सक्रिप्शन पृष्ठ जो उपयोक्ताों को कुछ फेरबदल करने की अनुमति देता है.
    1. उपयोक्ता सिर्फ ईमेल में रखे.
    2. ईमेल की भाषा चुनने की क्षमता.
    3. ईमेल की आवृत्ति चुनने की क्षमता.
      • यदि महीने का मासिक दिन चुनें...... यह भेजा गया है.
      • यदि सप्ताह का दिन चुना जाता है तो सप्ताह के दिन का चयन करें.
      • हर दिन की इजाज़त दीजिए (दिन का वक्‍त ज़रूरी नहीं है) ।
      • जब भी मैं ब्लॉग भेज दूं तो डाक संदेश भेजने की अनुमति दें.
    4. उपयोक्ता को चुनने की अनुमति दें जिसमें वे दिलचस्पी रखते हैं
  2. साधारण बिना सिफ़ारिश की अनुमति दें
  3. डाक का पूर्वावलोकन स्वीकारें जिसे वे प्राप्त करेंगे
  4. उपयोक्ता को अपनी पसंद को किसी भी समय बदलने दें.
  5. एक अलग सेवा जो ई- मेल भेजने से संभालता है.
    • यह सेवा ब्लॉग सेवा द्वारा बुलाया जाएगा जब भी कोई नया पोस्ट बनाया जाएगा.
    • तब यह सेवा सभी सदस्यता करनेवालों को ई- मेल भेज देगी.
    • यह ई- मेल भेजने को निर्धारित करने के लिए हैंग आग का उपयोग करेगा.

इस का प्रभाव है कि मुझे बहुत काम करना है.

सब्सक्रिप्शन पृष्ठ

मैं मज़े के साथ शुरू कर दिया एक अभिदान पृष्ठ लिख दिया. मैं इसे डेस्कटॉप पर अच्छी तरह से काम करना चाहता था साथ ही मोबाइल ब्राउज़र (और यहाँ तक कि) एसपीएसे मेरी उममी एक अजीब मैं मोबाइल उपकरणों से इस तीव्रता से उपयोक्ता पहुँच के उचित रूप से देख सकते हैं.

उमम क्रेड प्लेटफॉर्म

मैं भी सदस्यता पृष्ठ का उपयोग करने के लिए स्पष्ट होना चाहता था, मैं में एक बड़ा विश्वस्त हूँ स्टीव कुग के "मुझे लगता नहीं है" उस तत्त्वज्ञान को जहाँ एक पृष्ठ का उपयोग करने के लिए स्पष्ट होना चाहिए और इसे प्रयोग करने के लिए उपयोक्ता को यह सोचने की आवश्‍यकता नहीं है कि इसका कैसे प्रयोग करें ।

इसका अर्थ है कि डिफ़ॉल्ट उपयोक्ताओं में से अधिकांश उपयोग करना चाहेंगे. मैं निम्नलिखित डिफ़ॉल्ट पर फैसला किया:

  1. साप्ताहिक ईमेल
  2. अंग्रेज़ी भाषा
  3. सभी वर्ग चयनित
  4. सोमवार को ई- मेल भेजा गया

मैं निश्चित रूप से इस को बाद में बदल सकते हैं अगर ये गलत साबित हो.

तो यह है कि मैं दीवार को चोट लगी है:

सदस्यता पृष्ठ

पृष्ठ के लिए कोड

इस साइट के बाक़ी के रूप में मैं कोड को जितना संभव हो उतना सरल बनाना चाहता था । यह निम्न एचटीएमएल उपयोग करता है:

Subscription Page
@using Mostlylucid.Shared
@using Mostlylucid.Shared.Helpers
@model Mostlylucid.EmailSubscription.Models.EmailSubscribeViewModel

<form x-data="{schedule :'@Model.SubscriptionType'}" x-init="$watch('schedule', value => console.log(value))" hx-boost="true" asp-action="Save" asp-controller="EmailSubscription" 
      hx-target="#contentcontainer" hx-swap="#outerHTML">
    <div class="flex flex-col mb-4">
        <div class="flex flex-wrap lg:flex-nowrap lg:space-x-4 space-y-4 lg:space-y-0 items-start">
            <label class="input input-bordered flex items-center gap-2 mb-2 dark:bg-custom-dark-bg bg-white w-full lg:w-2/3">
                <i class='bx bx-envelope'></i>
                <input type="email" class="grow text-black dark:text-white bg-transparent border-0"
                       asp-for="Email" placeholder="Email (optional)"/>
            </label>
            <div class="grid grid-cols-2 sm:grid-cols-[repeat(auto-fit,minmax(100px,1fr))] w-full lg:w-1/3">
                @{
                    var frequency = Enum.GetValues(typeof(SubscriptionType)).Cast<SubscriptionType>().ToList();
                }
                @foreach (var freq in frequency)
                {
                    <div class="flex items-center w-auto h-full min-h-[30px] lg:mb-0 mb-3">
                        <input x-model="schedule" id="@freq" type="radio" value="@freq.ToString()" name="SubscriptionType" class="hidden peer">
                        <label for="@freq" class="ml-2 text-sm font-medium text-white 
                bg-blue-dark border-gray-light border rounded-xl px-1 py-2 w-full 
                peer-checked:text-blue-600 peer-checked:dark:bg-green text-center justify-center">
                            @freq.EnumDisplayName()
                        </label>
                    </div>
                }
            </div>
        </div>
        @{
            var languages = LanguageConverter.LanguageMap;
        }

        <div class="grid grid-cols-[repeat(auto-fit,minmax(85px,1fr))] mt-4 gap-2 pl-6 large:pl-0 w-auto">
            @foreach (var language in languages)
            {
                var [email protected] == language.Key ? "checked" : "";
                <div class="tooltip lg:mb-0 mb-2" data-tip="@language.Value)"  >
                    <div class="flex items-center justify-center w-[85px] h-full min-h-[70px]">
                        <input id="@language.Key" type="radio" value="@language.Key" @isChecked name="language" class="hidden peer">
                        <label for="@language.Key" class="flex flex-col items-center justify-center text-sm font-medium text-white bg-blue-dark opacity-50 peer-checked:opacity-100 w-full h-full">
                            <img src="/img/flags/@(language.Key).svg" asp-append-version="true" class="border-gray-light border rounded-l w-full h-full object-cover" alt="@language.Value">
                        </label>
                    </div>

                </div>
            }
        </div>
        <div class="mt-3 border-neutral-400 dark:border-neutral-600 border rounded-lg" x-data="{ hideCategories: false, showCategories: false }">
            <h4
                class="px-5 py-1 bg-neutral-500 bg-opacity-10 rounded-lg font-body text-primary dark:text-white w-full flex justify-between items-center cursor-pointer"
                x-on:click="if(!hideCategories) { showCategories = !showCategories }">
                <span class="flex flex-row items-center space-x-1">
                    Categories
                    <label class="label cursor-pointer ml-4" x-on:click.stop="">
                        all
                    </label>
                    <input type="checkbox" x-on:click.stop="" x-model="hideCategories" asp-for="AllCategories" class="toggle toggle-info toggle-sm" />
                </span>
                <span>
                    <i
                        class="bx text-2xl"
                        x-show="!hideCategories"
                        :class="showCategories ? 'bx-chevron-up' : 'bx-chevron-down'"></i>
                </span>
            </h4>

            <div class="flex flex-wrap gap-2 pt-2 pl-5 pr-5 pb-2"
                x-show="showCategories"
                x-cloak
                x-transition:enter="max-h-0 opacity-0"
                x-transition:enter-end="max-h-screen opacity-100"
                x-transition:leave="max-h-screen opacity-100"
                x-transition:leave-end="max-h-0 opacity-0">
                <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] mt-4 w-full">
                    @foreach (var category in Model.Categories)
                    {
                        var categoryKey = category.Replace(" ", "_").Replace(".", "_").Replace("-", "_");
                        <div class="flex items-center w-auto h-full min-h-[50px]">
                            <input id="@categoryKey" type="checkbox" value="@category"  name="@nameof(Model.SelectedCategories)" class="hidden peer">
                            <label for="@categoryKey" class="ml-2 text-sm font-medium text-white 
            bg-blue-dark border-gray-light border rounded-xl px-1 py-2 w-full 
            peer-checked:text-blue-600 peer-checked:dark:bg-green text-center justify-center">
                                @category
                            </label>
                        </div>
                    }
                </div>
            </div></div>


        <div :class="{ 'opacity-50 pointer-events-none': schedule !== 'Weekly' }" class=" mt-2 border-neutral-400 dark:border-neutral-600 border rounded-lg" >
            <h4
                class="px-5 py-1 bg-neutral-500 bg-opacity-10 rounded-lg font-body text-primary dark:text-white w-full flex justify-between items-center cursor-pointer"
               >
                <span class="flex flex-row items-center space-x-1 ">
                    Day of Week to Send On
                    
                  
                </span>
               
            </h4>

        <div class="grid grid-cols-3 sm:grid-cols-[repeat(auto-fit,minmax(80px,1fr))] my-2 w-full lg:w-1/2" x-show="schedule === 'Weekly'">
            @foreach (var day in Model.DaysOfWeek)
            {
                var checkedDay = day.ToString() == Model.Day ? "checked" : "";
                <div class="flex items-center w-auto h-full min-h-[50px]">
                    <input id="@day" type="radio" value="@day" name="day" @checkedDay class="hidden peer">
                    <label for="@day" class="ml-2 text-sm font-medium text-white 
            bg-blue-dark border-gray-light border rounded-xl px-1 py-2 w-full 
            peer-checked:text-blue-600 peer-checked:dark:bg-green text-center justify-center">
                        @day.ToString()
                    </label>
                </div>
            }
        </div>

            </div>
        <div :class="{ 'opacity-50 pointer-events-none': schedule !== 'Monthly' }" class=" mt-2 border-neutral-400 dark:border-neutral-600 border rounded-lg" >
            <h4
                class="px-5 py-1 bg-neutral-500 bg-opacity-10 rounded-lg font-body text-primary dark:text-white w-full flex justify-between items-center cursor-pointer">
                <span class="flex flex-row items-center space-x-1 ">
                    Day of Month to Send On
                </span>
            </h4>
            <div class="grid grid-cols-[repeat(auto-fit,minmax(35px,1fr))] w-full mx-2" x-show="schedule === 'Monthly'">
                @for(int i=1; i<32; i++)
                {
                    var checkedMonthDay = i == Model.DayOfMonth ? "checked" : "";
                    <div class="flex items-center w-auto my-2 h-full min-h-[35px]">
                        <input id="Day_@i" type="radio" value="@i" name="daypfmonth" @checkedMonthDay class="hidden peer">
                        <label for="Day_@i" class="ml-2 text-sm font-medium text-white 
            bg-blue-dark border-gray-light border rounded-xl px-1 py-2 w-full 
            peer-checked:text-blue-600 peer-checked:dark:bg-green text-center justify-center">
                             @i.GetOrdinal()
                        </label>
                    </div>
                }
            </div>
        </div>
        @* Action Buttons *@
        <div class="flex flex-row gap-2 mt-4">
            <button type="submit" class="btn btn-primary">Subscribe</button>
            <button type="reset" class="btn-warning btn">Reset</button>
        </div>
    </div>
</form>
आप देख सकते हैं कि यह बहुत सरल है के रूप में यह चला जाता है. यह सभी उपयोगकर्ता संपर्कों और सभी चुनावों के लिए एक सामान्य यूआई तत्व का उपयोग करने के लिए आपेक्षित सुविधा का उपयोग करता है.
<div class="grid grid-cols-2 sm:grid-cols-[repeat(auto-fit,minmax(100px,1fr))] w-full lg:w-1/3">
 @{
var frequency = Enum.GetValues(typeof(SubscriptionType)).Cast<SubscriptionType>().ToList();
 }
 @foreach (var freq in frequency)
{
<div class="flex items-center w-auto h-full min-h-[30px] lg:mb-0 mb-3">
     <input x-model="schedule" id="@freq" type="radio" value="@freq.ToString()" name="SubscriptionType" class="hidden peer">
      <label for="@freq" class="ml-2 text-sm font-medium text-white 
                bg-blue-dark border-gray-light border rounded-xl px-1 py-2 w-full 
                peer-checked:text-blue-600 peer-checked:dark:bg-green text-center justify-center">
                            @freq.EnumDisplayName()
      </label>
</div>
}
</div>

आप देख सकते हैं कि यह सीएसएस आधारित है, टिलेज सीएसएस फ्रेमवर्क के उपयोग से peer यह निर्धारित करने के लिए सीएसएस यूटिलिटी यूटिलिटी कि जब लेबल इस पर क्लिक किया जाता है तो इनपुट की जांच की जाती है तथा इसे बदलता है.

मैं इसे बाद में पृष्ठ पर निर्धारित करता हूँ कि कौन से चयन को उपलब्ध करने के लिए (हम माह का दिन / माह का दिन) उपयोक्ताओं को उपलब्ध कर सकते हैं तथा तत्वों को चुनने की अनुमति देता है.

<div :class="{ 'opacity-50 pointer-events-none': schedule !== 'Monthly' }" class=" mt-2 border-neutral-400 dark:border-neutral-600 border rounded-lg" >
   <h4
       class="px-5 py-1 bg-neutral-500 bg-opacity-10 rounded-lg font-body text-primary dark:text-white w-full flex justify-between items-center cursor-pointer">
       <span class="flex flex-row items-center space-x-1 ">
           Day of Month to Send On
       </span>
   </h4>
   <div class="grid grid-cols-[repeat(auto-fit,minmax(35px,1fr))] w-full mx-2" x-show="schedule === 'Monthly'">
       @for(int i=1; i<32; i++)
       {
           var checkedMonthDay = i == Model.DayOfMonth ? "checked" : "";
           <div class="flex items-center w-auto my-2 h-full min-h-[35px]">
               <input id="Day_@i" type="radio" value="@i" name="daypfmonth" @checkedMonthDay class="hidden peer">
               <label for="Day_@i" class="ml-2 text-sm font-medium text-white 
   bg-blue-dark border-gray-light border rounded-xl px-1 py-2 w-full 
   peer-checked:text-blue-600 peer-checked:dark:bg-green text-center justify-center">
                    @i.GetOrdinal()
               </label>
           </div>
       }
   </div>
</div>

आप देख सकते हैं कि मेरे पास अप्रयोगात्मक ssss cs Cass वर्ग है जो तत्व की पारदर्शिता को 50% तक सेट करता है और संकेतक घटनाओं को निष्क्रिय करता है यदि नियत समय पर माह सेट नहीं किया गया है. यह उन तत्वों को छिपाने का सरल तरीका है जो जरूरी नहीं हैं.

:class="{ 'opacity-50 pointer-events-none': schedule !== 'Monthly' }" 

यदि निर्धारित समय माह में नहीं है तो यह राष्ट्रीय दिन चयनक भी दिखाता है.

x-show="schedule === 'Monthly'"

तो यही कारण है कि समयबद्ध पृष्ठ का संघर्ष है। मैं अगले पोस्ट में बैकेंड कवर होगा.

अगला कदम

अगले पोस्ट में मैं इसे पूरा करूँगा (जब मैं इसे खत्म करूँगा) परियोजना में नए पुनः परिवर्तन का उपयोग करने के लिए मुझे सेवा के लिए एक अलग वेब अनुप्रयोग का उपयोग करने की अनुमति दें जो हैनएफजिल और ई मेल सेवा के लिए. यह काफी परिवर्तन है जैसे मैं एक परियोजना से जाना चाहता हूँ Mostlylucid कई परियोजनाओं में सेवा साझा करने की अनुमति दें:

  1. Mostlylucid - मुख्य वेबसाइट परियोजना.

  2. Mostlylucid.SchedulerService - यह मुख्य है आग जो डाटाबेस इक्का करेगा, ईमेल बनाने और उन्हें भेजने के लिए.

  3. Mostlylucid.Services - जहाँ सेवाएँ रहते हैं जो शीर्ष स्तर के परियोजनाओं में डेटा वापस आती हैं

  4. Mostlylucid.Shared - सभी परियोजनाओं द्वारा इस्तेमाल किया गया सहायक और स्थिरांक.

  5. Mostlylucid.DbContext - परियोजना के लिए डाटाबेस संदर्भ.

आप इसे और अधिक जटिल रूप से व्यवस्था संरचना के लिए और अधिक जटिल रूप से देख सकते हैं, लेकिन इस मामले में यह परियोजना स्थिर रखने के लिए आवश्यक है। मैं इस श्रृंखला के बाकी में कैसे किया कवर करेंगे.

ऑन्टियम

मैं अभी भी यह सब करने के लिए काम की एक बात है. रीफ्रिंग कुछ जटिल है क्योंकि इसमें कई परतों को तंत्र में जोड़ने में शामिल है (और धारणाएँ परियोजना के लिए DTO की तरह हैं) लेकिन मुझे लगता है कि यह लंबे समय से चल रहा है.

logo

©2024 Scott Galloway