The next pieces of functionality I’m adding to the site are all about flair. I really like a lot of the Community Server “sidebar” items, things like Most Recent Users, Most Active Users, etc. They really build upon the “community” aspect of Community Server. Because of this my initial WIWM user stories post included functionality on the home page for Most Recent Users and Recently Updated Wishlists. Another element I wanted to call out on the home page (and maybe in a sidebar on all pages) is a featured item or Hot Gift Idea. In addition to adding some helpful functionality to the site it will also add another revenue generating opportunity. “Buy Now” links can go to Amazon (or other affiliates) passing in my affiliate id.
I chose to group those items together and work on them in one session. Those with good observational skills may realize that I have not worked on my user stories in order of priority. Those people would be correct. While I would normally work on items in order of project importance or in order of risk, for this project I am taking a different approach. I am trying to work in bite-size chunks, grouping together a task or two that I can perform in an evening or in a couple of evenings at most. I have two reasons for doing so. One - for quicker turn-around, ensuring these posts come with some sort of frequency. If I went for two weeks without posting anything about WIWM you’d probably wonder what the hell I was doing that was taking so long or you’d think that I must have finally given up. The second reason is to keep the developer motivated. Implementing a couple of little tasks of lower priority that I am eager to work on might be a bit of a sin when I have higher priority items remaining. It is much better than the alternative: getting bogged down in something bigger that I really don’t want to do and dragging it out, maybe at the risk of not completing it altogether. So there’s another disclaimer for you - don’t necessarily do as I do.
This time around I’m going to reverse things up a bit by showing you the end result (the pretty picture) and then telling you what it took to get there. At the right you’ll see a screen capture of the current right hand sidebar of my home page, including Hot Gift Idea, Recent Members, and Recently Updated Wishlists. Clicking on the Zune image, find out more link or Amazon icon will take you to the Amazon site. Clicking on a username from one of the “recent” lists will take you to that user’s wishlist.
Looking at that image now, I realize that I missed something. I need a way to allow users to add the “featured item” to their wishlist. I’ll add that functionality next time I’m in there. I also think I will change “Recent Members” to “New Members”.
Since I explained in a previous post that I did not include any User objects in my .netTiers generated code (choosing to handle that all with ASP.NET 2.0 Membership), you’re probably wondering how I can list out the newest members. Well, not only can you generate objects, containers and services to handle your database tables with .netTiers, you can also generate strongly-typed objects, containers and services for any database views you specify. I created a new view, RecentMembers, that returns the top 10 most recently added usernames and dates by joining my wishlist table on the aspnet_membership table. I did something similar for the updated wishlists. I modified my .netTiers template to include those new views and after re-generating my code I had two new collections of objects with all their properties and methods for retrieving them. Once I had that in place, listing them out on the home page was a snap. I’ll describe only the process for the most recent members, but the updated wishlists code was nearly identical.
Because I didn’t know yet if I planned on putting the most recent users and other flair only on the homepage or in some universal sidebar or footer, I chose to create it in its own user control. I added the new user control, placed a datagrid on the page and then added the following code to the onLoad event of the code-behind:
//TODO: make use of some caching here
RecentMembersService memService = new RecentMembersService();
dg.DataSource = memService.GetAll();
dg.DataBind();
My database view handles the limiting of the results to the top 10 so I don’t have to worry about that in my code. You’ll also notice my TODO comment. Because this data will not change all that much and it really isn’t mission-critical there is no reason why I can’t make generous use of caching to ease the burden on my database server. I currently have several places in the code where I have put the same comment - at some point in the future I will return to them and make it so.
In a previous post I discussed creating an instance of the WishlistService and WishlistItemService in my BasePage class, making them properties of my Page object so they are available to every page. In this case my RecentMembersService will probably only be used in this one place so there is no reason to “promote” it to Page level scope.
My FeaturedItem object was already part of my framework - I knew I would need it from the beginning. No database modifications were needed to create the functionality to present it on the home page. Again I used a User Control, but no datagrid this time - just a couple of labels. The code to display the featured item looks something like this:
//TODO: Employ some caching here
FeaturedItemService fiService = new FeaturedItemService();
FeaturedItem fi = fiService.Get(1);
lblItemName.Text = fi.ProductName;
lnkBuyItAtAmazon.NavigateUrl = "http://www.amazon.com/gp/product/" + fi.AmazonID + "?tag=" + MyAmazonID;
lnkReadItAtAmazon.NavigateUrl = lnkFeaturedBuyItAtAmazon.NavigateUrl;
lnkItemImage.ImageUrl = "~/images/featured/" + fi.ImageUrl;
lnkItemImage.NavigateUrl = lnkFeaturedBuyItAtAmazon.NavigateUrl;
lblItemDesc.Text = fi.ProductDesc;
lblItemPrice.Text = String.Format("{0:c}", fi.Price);
//TODO: Add Link to Reviews
//TODO: Add "Search Web" AJAXY thing
Again, you’ll see the caching TODO. Also, for the FeaturedItemService.Get() call I currently have the id of “1” hard-coded in place. It’s nothing magic, I am just getting the item with an ID of 1 from the table. I haven’t yet decided if I will randomly show featured items from the database or if I will mark one of them as the current and allow administrators to change the current one when they want. Once I decide I will probably have to implement a custom stored procedure to retrieve the current one and then have .netTiers generate the method to call that stored proc. The only other things to point out is that as you can tell from the Urls I am currently sending everything to Amazon because I’ll get paid if someone buys something from there. Because I may later decide to use more than one store I might want to think about moving that URL generation logic somewhere else. For now, though, I’ll adopt the YAGNI rule (You Ain’t Gonna Need It) and not worry about it yet. However, I don’t like the hard-coded Url string in the code. In fact I realize that I have the same string hard-coded into a couple different pages now. That elicits a “code smell”, doesn’t it? I will want to look into doing something else with those soon: either creating a helper function that returns those Urls or moving the string into the web.config file or both. Finally, you can see from the other TODO’s that this does not do 100% fo what I would like it to yet. However, it is close enough for me to cross the item off my list. For the most part the remaining pieces are just “nice to have” functionality and I can break them out of this user story into a task of their own.
Despite the fact that I have not been implementing the user stories in any specific order I have been crossing them off my list as I implement them. Surprisingly, there are only a few remaining that absolutely must be implemented for the site to go live. Two of the four remaining have to do with sending emails to people so that they can view your wishlist, one of them is about editing your profile (which I have already done some work on), and the final probably has more to do with CSS than anything else (printer friendly wishlist). These items are where I will concentrate my efforts next. Additionally, soon I should return to my list of user stories and break down any of the larger ones into smaller tasks, add any new tasks that I have discovered (ex: “add to wishlist” link from the featured item), and add tasks that didn’t get implemented as part of other stories (ex: the reviews that got “bumped” from the featured item).